diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..48ff532b2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +# Ignore changes in generated files +src/generated/resources/data/** linguist-generated + +* text=auto + +*.gradle eol=lf diff=java +*.java eol=lf diff=java +*.kt eol=lf diff=java +*.lua eol=lf +*.md eol=lf diff=markdown +*.txt eol=lf + +*.png binary +*.jar binary +*.dfpwm binary diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 014abc079..c2df1eb81 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -12,10 +12,10 @@ jobs: with: submodules: true - - name: Set up Java 16 + - name: Set up Java 17 uses: actions/setup-java@v1 with: - java-version: 16 + java-version: 17 - name: Cache gradle dependencies uses: actions/cache@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 66d760891..c3533f270 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,6 +25,9 @@ jobs: with: java-version: 17 + - name: Pull submodules + run: git submodule update --init --recursive + - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/.gitignore b/.gitignore index 8288d3541..a61a3b460 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ *.DS_Store .project *.launch + +/src/generated/resources/.cache diff --git a/build.gradle b/build.gradle index 22f551eb3..a0f2c9a96 100644 --- a/build.gradle +++ b/build.gradle @@ -3,8 +3,8 @@ plugins { id "jacoco" id "maven-publish" id "com.github.hierynomus.license" version "0.16.1" - id "org.jetbrains.kotlin.jvm" version "1.5.21" - id 'fabric-loom' version '0.10-SNAPSHOT' + id "org.jetbrains.kotlin.jvm" version "1.6.0" + id 'fabric-loom' version '0.11-SNAPSHOT' id "com.modrinth.minotaur" version "2.+" id 'com.matthewprenger.cursegradle' version '1.4.0' } @@ -40,6 +40,18 @@ sourceSets { loom { accessWidenerPath = file("src/main/resources/cc.accesswidener") + + runs { + data { + server() + + name "Data Generation" + vmArg "-Dfabric-api.datagen" + vmArg "-Dfabric-api.datagen.output-dir=${file("src/generated/resources")}" + + runDir "build/datagen" + } + } } repositories { @@ -92,10 +104,11 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' testImplementation 'org.hamcrest:hamcrest:2.2' - testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21' - testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1' + testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.0' + testImplementation 'org.jetbrains.kotlin:kotlin-reflect:1.6.0' + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' - cctJavadoc 'cc.tweaked:cct-javadoc:1.4.2' + cctJavadoc 'cc.tweaked:cct-javadoc:1.4.5' } processResources { diff --git a/doc/events/mouse_click.md b/doc/events/mouse_click.md index 83d371260..ed4f2e3eb 100644 --- a/doc/events/mouse_click.md +++ b/doc/events/mouse_click.md @@ -19,8 +19,8 @@ numerical value depending on which button on your mouse was last pressed when th Button codeMouse button 1Left button - 2Middle button - 3Right button + 2Right button + 3Middle button ## Example diff --git a/gradle.properties b/gradle.properties index e5df156c2..f63a329e7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,11 +2,11 @@ org.gradle.jvmargs=-Xmx3G # Mod properties -mod_version=1.100.5 +mod_version=1.100.6 # Minecraft properties mc_version=1.18.2 -fabric_api_version=0.47.8+1.18.2 +fabric_api_version=0.51.1+1.18.2 fabric_loader_version=0.13.3 cloth_api_version=2.0.54 diff --git a/jitpack.yml b/jitpack.yml index b6056a9b3..10f7636fe 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,5 +1,5 @@ before_install: - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh - - source ./install-jdk.sh --feature 16 --license GPL + - source ./install-jdk.sh --feature 17 --license GPL jdk: - openjdk16 diff --git a/src/generated/resources/assets/computercraft/blockstates/computer_advanced.json b/src/generated/resources/assets/computercraft/blockstates/computer_advanced.json new file mode 100644 index 000000000..9577ea9b4 --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/computer_advanced.json @@ -0,0 +1,52 @@ +{ + "variants": { + "facing=east,state=blinking": { + "y": 90, + "model": "computercraft:block/computer_advanced_blinking" + }, + "facing=east,state=off": { + "y": 90, + "model": "computercraft:block/computer_advanced_off" + }, + "facing=east,state=on": { + "y": 90, + "model": "computercraft:block/computer_advanced_on" + }, + "facing=north,state=blinking": { + "y": 0, + "model": "computercraft:block/computer_advanced_blinking" + }, + "facing=north,state=off": { + "y": 0, + "model": "computercraft:block/computer_advanced_off" + }, + "facing=north,state=on": { + "y": 0, + "model": "computercraft:block/computer_advanced_on" + }, + "facing=south,state=blinking": { + "y": 180, + "model": "computercraft:block/computer_advanced_blinking" + }, + "facing=south,state=off": { + "y": 180, + "model": "computercraft:block/computer_advanced_off" + }, + "facing=south,state=on": { + "y": 180, + "model": "computercraft:block/computer_advanced_on" + }, + "facing=west,state=blinking": { + "y": 270, + "model": "computercraft:block/computer_advanced_blinking" + }, + "facing=west,state=off": { + "y": 270, + "model": "computercraft:block/computer_advanced_off" + }, + "facing=west,state=on": { + "y": 270, + "model": "computercraft:block/computer_advanced_on" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/computer_command.json b/src/generated/resources/assets/computercraft/blockstates/computer_command.json new file mode 100644 index 000000000..1f811b2eb --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/computer_command.json @@ -0,0 +1,52 @@ +{ + "variants": { + "facing=east,state=blinking": { + "y": 90, + "model": "computercraft:block/computer_command_blinking" + }, + "facing=east,state=off": { + "y": 90, + "model": "computercraft:block/computer_command_off" + }, + "facing=east,state=on": { + "y": 90, + "model": "computercraft:block/computer_command_on" + }, + "facing=north,state=blinking": { + "y": 0, + "model": "computercraft:block/computer_command_blinking" + }, + "facing=north,state=off": { + "y": 0, + "model": "computercraft:block/computer_command_off" + }, + "facing=north,state=on": { + "y": 0, + "model": "computercraft:block/computer_command_on" + }, + "facing=south,state=blinking": { + "y": 180, + "model": "computercraft:block/computer_command_blinking" + }, + "facing=south,state=off": { + "y": 180, + "model": "computercraft:block/computer_command_off" + }, + "facing=south,state=on": { + "y": 180, + "model": "computercraft:block/computer_command_on" + }, + "facing=west,state=blinking": { + "y": 270, + "model": "computercraft:block/computer_command_blinking" + }, + "facing=west,state=off": { + "y": 270, + "model": "computercraft:block/computer_command_off" + }, + "facing=west,state=on": { + "y": 270, + "model": "computercraft:block/computer_command_on" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/computer_normal.json b/src/generated/resources/assets/computercraft/blockstates/computer_normal.json new file mode 100644 index 000000000..a91960e7b --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/computer_normal.json @@ -0,0 +1,52 @@ +{ + "variants": { + "facing=east,state=blinking": { + "y": 90, + "model": "computercraft:block/computer_normal_blinking" + }, + "facing=east,state=off": { + "y": 90, + "model": "computercraft:block/computer_normal_off" + }, + "facing=east,state=on": { + "y": 90, + "model": "computercraft:block/computer_normal_on" + }, + "facing=north,state=blinking": { + "y": 0, + "model": "computercraft:block/computer_normal_blinking" + }, + "facing=north,state=off": { + "y": 0, + "model": "computercraft:block/computer_normal_off" + }, + "facing=north,state=on": { + "y": 0, + "model": "computercraft:block/computer_normal_on" + }, + "facing=south,state=blinking": { + "y": 180, + "model": "computercraft:block/computer_normal_blinking" + }, + "facing=south,state=off": { + "y": 180, + "model": "computercraft:block/computer_normal_off" + }, + "facing=south,state=on": { + "y": 180, + "model": "computercraft:block/computer_normal_on" + }, + "facing=west,state=blinking": { + "y": 270, + "model": "computercraft:block/computer_normal_blinking" + }, + "facing=west,state=off": { + "y": 270, + "model": "computercraft:block/computer_normal_off" + }, + "facing=west,state=on": { + "y": 270, + "model": "computercraft:block/computer_normal_on" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json b/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json new file mode 100644 index 000000000..69f41596d --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json @@ -0,0 +1,964 @@ +{ + "variants": { + "facing=east,orientation=down,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=north,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=up,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 270, + "y": 90 + }, + "facing=north,orientation=down,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=north,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=up,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 270, + "y": 0 + }, + "facing=south,orientation=down,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=north,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=up,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 270, + "y": 180 + }, + "facing=west,orientation=down,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=north,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=up,state=d": { + "model": "computercraft:block/monitor_advanced_d", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=l": { + "model": "computercraft:block/monitor_advanced_l", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=ld": { + "model": "computercraft:block/monitor_advanced_ld", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lr": { + "model": "computercraft:block/monitor_advanced_lr", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lrd": { + "model": "computercraft:block/monitor_advanced_lrd", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lru": { + "model": "computercraft:block/monitor_advanced_lru", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lrud": { + "model": "computercraft:block/monitor_advanced_lrud", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lu": { + "model": "computercraft:block/monitor_advanced_lu", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lud": { + "model": "computercraft:block/monitor_advanced_lud", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=none": { + "model": "computercraft:block/monitor_advanced", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=r": { + "model": "computercraft:block/monitor_advanced_r", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=rd": { + "model": "computercraft:block/monitor_advanced_rd", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=ru": { + "model": "computercraft:block/monitor_advanced_ru", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=rud": { + "model": "computercraft:block/monitor_advanced_rud", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=u": { + "model": "computercraft:block/monitor_advanced_u", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=ud": { + "model": "computercraft:block/monitor_advanced_ud", + "x": 270, + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json b/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json new file mode 100644 index 000000000..f928cc82c --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json @@ -0,0 +1,964 @@ +{ + "variants": { + "facing=east,orientation=down,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 90, + "y": 90 + }, + "facing=east,orientation=down,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 90, + "y": 90 + }, + "facing=east,orientation=north,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 0, + "y": 90 + }, + "facing=east,orientation=north,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 0, + "y": 90 + }, + "facing=east,orientation=up,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 270, + "y": 90 + }, + "facing=east,orientation=up,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 270, + "y": 90 + }, + "facing=north,orientation=down,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 90, + "y": 0 + }, + "facing=north,orientation=down,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 90, + "y": 0 + }, + "facing=north,orientation=north,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 0, + "y": 0 + }, + "facing=north,orientation=north,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 0, + "y": 0 + }, + "facing=north,orientation=up,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 270, + "y": 0 + }, + "facing=north,orientation=up,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 270, + "y": 0 + }, + "facing=south,orientation=down,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 90, + "y": 180 + }, + "facing=south,orientation=down,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 90, + "y": 180 + }, + "facing=south,orientation=north,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 0, + "y": 180 + }, + "facing=south,orientation=north,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 0, + "y": 180 + }, + "facing=south,orientation=up,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 270, + "y": 180 + }, + "facing=south,orientation=up,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 270, + "y": 180 + }, + "facing=west,orientation=down,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 90, + "y": 270 + }, + "facing=west,orientation=down,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 90, + "y": 270 + }, + "facing=west,orientation=north,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 0, + "y": 270 + }, + "facing=west,orientation=north,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 0, + "y": 270 + }, + "facing=west,orientation=up,state=d": { + "model": "computercraft:block/monitor_normal_d", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=l": { + "model": "computercraft:block/monitor_normal_l", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=ld": { + "model": "computercraft:block/monitor_normal_ld", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lr": { + "model": "computercraft:block/monitor_normal_lr", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lrd": { + "model": "computercraft:block/monitor_normal_lrd", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lru": { + "model": "computercraft:block/monitor_normal_lru", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lrud": { + "model": "computercraft:block/monitor_normal_lrud", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lu": { + "model": "computercraft:block/monitor_normal_lu", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=lud": { + "model": "computercraft:block/monitor_normal_lud", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=none": { + "model": "computercraft:block/monitor_normal", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=r": { + "model": "computercraft:block/monitor_normal_r", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=rd": { + "model": "computercraft:block/monitor_normal_rd", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=ru": { + "model": "computercraft:block/monitor_normal_ru", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=rud": { + "model": "computercraft:block/monitor_normal_rud", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=u": { + "model": "computercraft:block/monitor_normal_u", + "x": 270, + "y": 270 + }, + "facing=west,orientation=up,state=ud": { + "model": "computercraft:block/monitor_normal_ud", + "x": 270, + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/speaker.json b/src/generated/resources/assets/computercraft/blockstates/speaker.json new file mode 100644 index 000000000..80f9a8f4f --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/speaker.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "computercraft:block/speaker", + "y": 90 + }, + "facing=north": { + "model": "computercraft:block/speaker" + }, + "facing=south": { + "model": "computercraft:block/speaker", + "y": 180 + }, + "facing=west": { + "model": "computercraft:block/speaker", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/wired_modem_full.json b/src/generated/resources/assets/computercraft/blockstates/wired_modem_full.json new file mode 100644 index 000000000..bdae6829f --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/wired_modem_full.json @@ -0,0 +1,16 @@ +{ + "variants": { + "modem=false,peripheral=false": { + "model": "computercraft:block/wired_modem_full_off" + }, + "modem=false,peripheral=true": { + "model": "computercraft:block/wired_modem_full_off_peripheral" + }, + "modem=true,peripheral=false": { + "model": "computercraft:block/wired_modem_full_on" + }, + "modem=true,peripheral=true": { + "model": "computercraft:block/wired_modem_full_on_peripheral" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/wireless_modem_advanced.json b/src/generated/resources/assets/computercraft/blockstates/wireless_modem_advanced.json new file mode 100644 index 000000000..558c0a7c8 --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/wireless_modem_advanced.json @@ -0,0 +1,64 @@ +{ + "variants": { + "facing=down,on=false": { + "x": 90, + "y": 0, + "model": "computercraft:block/wireless_modem_advanced_off" + }, + "facing=down,on=true": { + "x": 90, + "y": 0, + "model": "computercraft:block/wireless_modem_advanced_on" + }, + "facing=east,on=false": { + "x": 0, + "y": 90, + "model": "computercraft:block/wireless_modem_advanced_off" + }, + "facing=east,on=true": { + "x": 0, + "y": 90, + "model": "computercraft:block/wireless_modem_advanced_on" + }, + "facing=north,on=false": { + "x": 0, + "y": 0, + "model": "computercraft:block/wireless_modem_advanced_off" + }, + "facing=north,on=true": { + "x": 0, + "y": 0, + "model": "computercraft:block/wireless_modem_advanced_on" + }, + "facing=south,on=false": { + "x": 0, + "y": 180, + "model": "computercraft:block/wireless_modem_advanced_off" + }, + "facing=south,on=true": { + "x": 0, + "y": 180, + "model": "computercraft:block/wireless_modem_advanced_on" + }, + "facing=up,on=false": { + "x": 270, + "y": 0, + "model": "computercraft:block/wireless_modem_advanced_off" + }, + "facing=up,on=true": { + "x": 270, + "y": 0, + "model": "computercraft:block/wireless_modem_advanced_on" + }, + "facing=west,on=false": { + "x": 0, + "y": 270, + "model": "computercraft:block/wireless_modem_advanced_off" + }, + "facing=west,on=true": { + "x": 0, + "y": 270, + "model": "computercraft:block/wireless_modem_advanced_on" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/wireless_modem_normal.json b/src/generated/resources/assets/computercraft/blockstates/wireless_modem_normal.json new file mode 100644 index 000000000..6194bb769 --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/wireless_modem_normal.json @@ -0,0 +1,64 @@ +{ + "variants": { + "facing=down,on=false": { + "x": 90, + "y": 0, + "model": "computercraft:block/wireless_modem_normal_off" + }, + "facing=down,on=true": { + "x": 90, + "y": 0, + "model": "computercraft:block/wireless_modem_normal_on" + }, + "facing=east,on=false": { + "x": 0, + "y": 90, + "model": "computercraft:block/wireless_modem_normal_off" + }, + "facing=east,on=true": { + "x": 0, + "y": 90, + "model": "computercraft:block/wireless_modem_normal_on" + }, + "facing=north,on=false": { + "x": 0, + "y": 0, + "model": "computercraft:block/wireless_modem_normal_off" + }, + "facing=north,on=true": { + "x": 0, + "y": 0, + "model": "computercraft:block/wireless_modem_normal_on" + }, + "facing=south,on=false": { + "x": 0, + "y": 180, + "model": "computercraft:block/wireless_modem_normal_off" + }, + "facing=south,on=true": { + "x": 0, + "y": 180, + "model": "computercraft:block/wireless_modem_normal_on" + }, + "facing=up,on=false": { + "x": 270, + "y": 0, + "model": "computercraft:block/wireless_modem_normal_off" + }, + "facing=up,on=true": { + "x": 270, + "y": 0, + "model": "computercraft:block/wireless_modem_normal_on" + }, + "facing=west,on=false": { + "x": 0, + "y": 270, + "model": "computercraft:block/wireless_modem_normal_off" + }, + "facing=west,on=true": { + "x": 0, + "y": 270, + "model": "computercraft:block/wireless_modem_normal_on" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json b/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json new file mode 100644 index 000000000..8f38a1426 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/computer_advanced_top", + "front": "computercraft:block/computer_advanced_front_blink", + "side": "computercraft:block/computer_advanced_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_advanced_off.json b/src/generated/resources/assets/computercraft/models/block/computer_advanced_off.json new file mode 100644 index 000000000..a5f377ce2 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_advanced_off.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/computer_advanced_top", + "front": "computercraft:block/computer_advanced_front", + "side": "computercraft:block/computer_advanced_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json b/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json new file mode 100644 index 000000000..b85966988 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/computer_advanced_top", + "front": "computercraft:block/computer_advanced_front_on", + "side": "computercraft:block/computer_advanced_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json b/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json new file mode 100644 index 000000000..991b698f0 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/computer_command_top", + "front": "computercraft:block/computer_command_front_blink", + "side": "computercraft:block/computer_command_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_command_off.json b/src/generated/resources/assets/computercraft/models/block/computer_command_off.json new file mode 100644 index 000000000..35021b763 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_command_off.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/computer_command_top", + "front": "computercraft:block/computer_command_front", + "side": "computercraft:block/computer_command_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_command_on.json b/src/generated/resources/assets/computercraft/models/block/computer_command_on.json new file mode 100644 index 000000000..57016e47a --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_command_on.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/computer_command_top", + "front": "computercraft:block/computer_command_front_on", + "side": "computercraft:block/computer_command_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json b/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json new file mode 100644 index 000000000..b56958cc2 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/computer_normal_top", + "front": "computercraft:block/computer_normal_front_blink", + "side": "computercraft:block/computer_normal_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_normal_off.json b/src/generated/resources/assets/computercraft/models/block/computer_normal_off.json new file mode 100644 index 000000000..a0b673d23 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_normal_off.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/computer_normal_top", + "front": "computercraft:block/computer_normal_front", + "side": "computercraft:block/computer_normal_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json b/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json new file mode 100644 index 000000000..662c3bef5 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/computer_normal_top", + "front": "computercraft:block/computer_normal_front_on", + "side": "computercraft:block/computer_normal_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced.json new file mode 100644 index 000000000..a13f34e05 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_16", + "side": "computercraft:block/monitor_advanced_4", + "top": "computercraft:block/monitor_advanced_0", + "back": "computercraft:block/monitor_advanced_32" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_d.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_d.json new file mode 100644 index 000000000..ff39d102c --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_d.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_20", + "side": "computercraft:block/monitor_advanced_7", + "top": "computercraft:block/monitor_advanced_0", + "back": "computercraft:block/monitor_advanced_36" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_item.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_item.json new file mode 100644 index 000000000..aad0ced5f --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_item.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_15", + "side": "computercraft:block/monitor_advanced_4", + "top": "computercraft:block/monitor_advanced_0", + "back": "computercraft:block/monitor_advanced_32" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_l.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_l.json new file mode 100644 index 000000000..3bfb91292 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_l.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_19", + "side": "computercraft:block/monitor_advanced_4", + "top": "computercraft:block/monitor_advanced_1", + "back": "computercraft:block/monitor_advanced_33" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ld.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ld.json new file mode 100644 index 000000000..25269670d --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ld.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_31", + "side": "computercraft:block/monitor_advanced_7", + "top": "computercraft:block/monitor_advanced_1", + "back": "computercraft:block/monitor_advanced_45" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lr.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lr.json new file mode 100644 index 000000000..d94c3a5cf --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lr.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_18", + "side": "computercraft:block/monitor_advanced_4", + "top": "computercraft:block/monitor_advanced_2", + "back": "computercraft:block/monitor_advanced_34" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrd.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrd.json new file mode 100644 index 000000000..0de1d3268 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrd.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_30", + "side": "computercraft:block/monitor_advanced_7", + "top": "computercraft:block/monitor_advanced_2", + "back": "computercraft:block/monitor_advanced_46" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lru.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lru.json new file mode 100644 index 000000000..a28abc853 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lru.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_24", + "side": "computercraft:block/monitor_advanced_5", + "top": "computercraft:block/monitor_advanced_2", + "back": "computercraft:block/monitor_advanced_40" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrud.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrud.json new file mode 100644 index 000000000..9759d442e --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrud.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_27", + "side": "computercraft:block/monitor_advanced_6", + "top": "computercraft:block/monitor_advanced_2", + "back": "computercraft:block/monitor_advanced_43" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lu.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lu.json new file mode 100644 index 000000000..038626c68 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lu.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_25", + "side": "computercraft:block/monitor_advanced_5", + "top": "computercraft:block/monitor_advanced_1", + "back": "computercraft:block/monitor_advanced_39" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lud.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lud.json new file mode 100644 index 000000000..38e9374aa --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lud.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_28", + "side": "computercraft:block/monitor_advanced_6", + "top": "computercraft:block/monitor_advanced_1", + "back": "computercraft:block/monitor_advanced_42" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_r.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_r.json new file mode 100644 index 000000000..555aab92c --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_r.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_17", + "side": "computercraft:block/monitor_advanced_4", + "top": "computercraft:block/monitor_advanced_3", + "back": "computercraft:block/monitor_advanced_35" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rd.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rd.json new file mode 100644 index 000000000..22e0195b7 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rd.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_29", + "side": "computercraft:block/monitor_advanced_7", + "top": "computercraft:block/monitor_advanced_3", + "back": "computercraft:block/monitor_advanced_47" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ru.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ru.json new file mode 100644 index 000000000..6a503312a --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ru.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_23", + "side": "computercraft:block/monitor_advanced_5", + "top": "computercraft:block/monitor_advanced_3", + "back": "computercraft:block/monitor_advanced_41" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rud.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rud.json new file mode 100644 index 000000000..70cd94b68 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rud.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_26", + "side": "computercraft:block/monitor_advanced_6", + "top": "computercraft:block/monitor_advanced_3", + "back": "computercraft:block/monitor_advanced_44" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_u.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_u.json new file mode 100644 index 000000000..8c2271ce7 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_u.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_22", + "side": "computercraft:block/monitor_advanced_5", + "top": "computercraft:block/monitor_advanced_0", + "back": "computercraft:block/monitor_advanced_38" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ud.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ud.json new file mode 100644 index 000000000..481c8402d --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ud.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_advanced_21", + "side": "computercraft:block/monitor_advanced_6", + "top": "computercraft:block/monitor_advanced_0", + "back": "computercraft:block/monitor_advanced_37" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal.json new file mode 100644 index 000000000..b08678497 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_16", + "side": "computercraft:block/monitor_normal_4", + "top": "computercraft:block/monitor_normal_0", + "back": "computercraft:block/monitor_normal_32" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_d.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_d.json new file mode 100644 index 000000000..3d6137782 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_d.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_20", + "side": "computercraft:block/monitor_normal_7", + "top": "computercraft:block/monitor_normal_0", + "back": "computercraft:block/monitor_normal_36" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_item.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_item.json new file mode 100644 index 000000000..167ef1121 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_item.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_15", + "side": "computercraft:block/monitor_normal_4", + "top": "computercraft:block/monitor_normal_0", + "back": "computercraft:block/monitor_normal_32" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_l.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_l.json new file mode 100644 index 000000000..3f863819a --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_l.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_19", + "side": "computercraft:block/monitor_normal_4", + "top": "computercraft:block/monitor_normal_1", + "back": "computercraft:block/monitor_normal_33" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_ld.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ld.json new file mode 100644 index 000000000..860b84d7d --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ld.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_31", + "side": "computercraft:block/monitor_normal_7", + "top": "computercraft:block/monitor_normal_1", + "back": "computercraft:block/monitor_normal_45" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lr.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lr.json new file mode 100644 index 000000000..c69bab42d --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lr.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_18", + "side": "computercraft:block/monitor_normal_4", + "top": "computercraft:block/monitor_normal_2", + "back": "computercraft:block/monitor_normal_34" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrd.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrd.json new file mode 100644 index 000000000..3dd8543a7 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrd.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_30", + "side": "computercraft:block/monitor_normal_7", + "top": "computercraft:block/monitor_normal_2", + "back": "computercraft:block/monitor_normal_46" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lru.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lru.json new file mode 100644 index 000000000..c0fe995ee --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lru.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_24", + "side": "computercraft:block/monitor_normal_5", + "top": "computercraft:block/monitor_normal_2", + "back": "computercraft:block/monitor_normal_40" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrud.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrud.json new file mode 100644 index 000000000..61545472f --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrud.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_27", + "side": "computercraft:block/monitor_normal_6", + "top": "computercraft:block/monitor_normal_2", + "back": "computercraft:block/monitor_normal_43" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lu.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lu.json new file mode 100644 index 000000000..5572eb3bc --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lu.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_25", + "side": "computercraft:block/monitor_normal_5", + "top": "computercraft:block/monitor_normal_1", + "back": "computercraft:block/monitor_normal_39" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lud.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lud.json new file mode 100644 index 000000000..ba56cd1cd --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lud.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_28", + "side": "computercraft:block/monitor_normal_6", + "top": "computercraft:block/monitor_normal_1", + "back": "computercraft:block/monitor_normal_42" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_r.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_r.json new file mode 100644 index 000000000..bcbb7ef76 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_r.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_17", + "side": "computercraft:block/monitor_normal_4", + "top": "computercraft:block/monitor_normal_3", + "back": "computercraft:block/monitor_normal_35" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_rd.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_rd.json new file mode 100644 index 000000000..469f486c0 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_rd.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_29", + "side": "computercraft:block/monitor_normal_7", + "top": "computercraft:block/monitor_normal_3", + "back": "computercraft:block/monitor_normal_47" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_ru.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ru.json new file mode 100644 index 000000000..ca937ffa3 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ru.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_23", + "side": "computercraft:block/monitor_normal_5", + "top": "computercraft:block/monitor_normal_3", + "back": "computercraft:block/monitor_normal_41" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_rud.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_rud.json new file mode 100644 index 000000000..21fb19602 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_rud.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_26", + "side": "computercraft:block/monitor_normal_6", + "top": "computercraft:block/monitor_normal_3", + "back": "computercraft:block/monitor_normal_44" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_u.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_u.json new file mode 100644 index 000000000..a93b45be8 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_u.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_22", + "side": "computercraft:block/monitor_normal_5", + "top": "computercraft:block/monitor_normal_0", + "back": "computercraft:block/monitor_normal_38" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_ud.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ud.json new file mode 100644 index 000000000..ff10350c8 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ud.json @@ -0,0 +1,9 @@ +{ + "parent": "computercraft:block/monitor_base", + "textures": { + "front": "computercraft:block/monitor_normal_21", + "side": "computercraft:block/monitor_normal_6", + "top": "computercraft:block/monitor_normal_0", + "back": "computercraft:block/monitor_normal_37" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/speaker.json b/src/generated/resources/assets/computercraft/models/block/speaker.json new file mode 100644 index 000000000..340881c78 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/speaker.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/orientable", + "textures": { + "top": "computercraft:block/speaker_top", + "front": "computercraft:block/speaker_front", + "side": "computercraft:block/speaker_side" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wired_modem_full_off.json b/src/generated/resources/assets/computercraft/models/block/wired_modem_full_off.json new file mode 100644 index 000000000..35bbacc4e --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wired_modem_full_off.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "computercraft:block/wired_modem_face" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wired_modem_full_off_peripheral.json b/src/generated/resources/assets/computercraft/models/block/wired_modem_full_off_peripheral.json new file mode 100644 index 000000000..6f2d069b2 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wired_modem_full_off_peripheral.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "computercraft:block/wired_modem_face_peripheral" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wired_modem_full_on.json b/src/generated/resources/assets/computercraft/models/block/wired_modem_full_on.json new file mode 100644 index 000000000..67e3c7b5e --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wired_modem_full_on.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "computercraft:block/wired_modem_face_on" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wired_modem_full_on_peripheral.json b/src/generated/resources/assets/computercraft/models/block/wired_modem_full_on_peripheral.json new file mode 100644 index 000000000..6dff54d30 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wired_modem_full_on_peripheral.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "computercraft:block/wired_modem_face_peripheral_on" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wired_modem_off.json b/src/generated/resources/assets/computercraft/models/block/wired_modem_off.json new file mode 100644 index 000000000..b629be888 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wired_modem_off.json @@ -0,0 +1,7 @@ +{ + "parent": "computercraft:block/modem", + "textures": { + "front": "computercraft:block/wired_modem_face", + "back": "computercraft:block/modem_back" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wired_modem_off_peripheral.json b/src/generated/resources/assets/computercraft/models/block/wired_modem_off_peripheral.json new file mode 100644 index 000000000..7fea9f091 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wired_modem_off_peripheral.json @@ -0,0 +1,7 @@ +{ + "parent": "computercraft:block/modem", + "textures": { + "front": "computercraft:block/wired_modem_face_peripheral", + "back": "computercraft:block/modem_back" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wired_modem_on.json b/src/generated/resources/assets/computercraft/models/block/wired_modem_on.json new file mode 100644 index 000000000..93a8d9fc0 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wired_modem_on.json @@ -0,0 +1,7 @@ +{ + "parent": "computercraft:block/modem", + "textures": { + "front": "computercraft:block/wired_modem_face_on", + "back": "computercraft:block/modem_back" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wired_modem_on_peripheral.json b/src/generated/resources/assets/computercraft/models/block/wired_modem_on_peripheral.json new file mode 100644 index 000000000..32cf21f24 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wired_modem_on_peripheral.json @@ -0,0 +1,7 @@ +{ + "parent": "computercraft:block/modem", + "textures": { + "front": "computercraft:block/wired_modem_face_peripheral_on", + "back": "computercraft:block/modem_back" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wireless_modem_advanced_off.json b/src/generated/resources/assets/computercraft/models/block/wireless_modem_advanced_off.json new file mode 100644 index 000000000..5bac5468e --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wireless_modem_advanced_off.json @@ -0,0 +1,7 @@ +{ + "parent": "computercraft:block/modem", + "textures": { + "front": "computercraft:block/wireless_modem_advanced_face", + "back": "computercraft:block/modem_back" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wireless_modem_advanced_on.json b/src/generated/resources/assets/computercraft/models/block/wireless_modem_advanced_on.json new file mode 100644 index 000000000..c57b07dd9 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wireless_modem_advanced_on.json @@ -0,0 +1,7 @@ +{ + "parent": "computercraft:block/modem", + "textures": { + "front": "computercraft:block/wireless_modem_advanced_face_on", + "back": "computercraft:block/modem_back" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wireless_modem_normal_off.json b/src/generated/resources/assets/computercraft/models/block/wireless_modem_normal_off.json new file mode 100644 index 000000000..793df335a --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wireless_modem_normal_off.json @@ -0,0 +1,7 @@ +{ + "parent": "computercraft:block/modem", + "textures": { + "front": "computercraft:block/wireless_modem_normal_face", + "back": "computercraft:block/modem_back" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/wireless_modem_normal_on.json b/src/generated/resources/assets/computercraft/models/block/wireless_modem_normal_on.json new file mode 100644 index 000000000..5bc2e8e35 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/wireless_modem_normal_on.json @@ -0,0 +1,7 @@ +{ + "parent": "computercraft:block/modem", + "textures": { + "front": "computercraft:block/wireless_modem_normal_face_on", + "back": "computercraft:block/modem_back" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/computer_advanced.json b/src/generated/resources/assets/computercraft/models/item/computer_advanced.json new file mode 100644 index 000000000..a22f16b21 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/computer_advanced.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/computer_advanced_blinking" +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/computer_command.json b/src/generated/resources/assets/computercraft/models/item/computer_command.json new file mode 100644 index 000000000..b1e795493 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/computer_command.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/computer_command_blinking" +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/computer_normal.json b/src/generated/resources/assets/computercraft/models/item/computer_normal.json new file mode 100644 index 000000000..11327e98e --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/computer_normal.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/computer_normal_blinking" +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/monitor_advanced.json b/src/generated/resources/assets/computercraft/models/item/monitor_advanced.json new file mode 100644 index 000000000..62080d5e9 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/monitor_advanced.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/monitor_advanced_item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/monitor_normal.json b/src/generated/resources/assets/computercraft/models/item/monitor_normal.json new file mode 100644 index 000000000..62f812992 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/monitor_normal.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/monitor_normal_item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/speaker.json b/src/generated/resources/assets/computercraft/models/item/speaker.json new file mode 100644 index 000000000..b1512e00a --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/speaker.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/speaker" +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/wired_modem.json b/src/generated/resources/assets/computercraft/models/item/wired_modem.json new file mode 100644 index 000000000..aba155aab --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/wired_modem.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/wired_modem_off" +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/wired_modem_full.json b/src/generated/resources/assets/computercraft/models/item/wired_modem_full.json new file mode 100644 index 000000000..339d9842e --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/wired_modem_full.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/wired_modem_full_off" +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/wireless_modem_advanced.json b/src/generated/resources/assets/computercraft/models/item/wireless_modem_advanced.json new file mode 100644 index 000000000..4398d6086 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/wireless_modem_advanced.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/wireless_modem_advanced_off" +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/item/wireless_modem_normal.json b/src/generated/resources/assets/computercraft/models/item/wireless_modem_normal.json new file mode 100644 index 000000000..970e4be3e --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/item/wireless_modem_normal.json @@ -0,0 +1,3 @@ +{ + "parent": "computercraft:block/wireless_modem_normal_off" +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/items/ender_pearls.json b/src/generated/resources/data/c/tags/items/ender_pearls.json new file mode 100644 index 000000000..0b410745d --- /dev/null +++ b/src/generated/resources/data/c/tags/items/ender_pearls.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:ender_pearl" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/items/gold_blocks.json b/src/generated/resources/data/c/tags/items/gold_blocks.json new file mode 100644 index 000000000..863d47ad2 --- /dev/null +++ b/src/generated/resources/data/c/tags/items/gold_blocks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:gold_block" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/items/skulls.json b/src/generated/resources/data/c/tags/items/skulls.json new file mode 100644 index 000000000..b5a3caaf2 --- /dev/null +++ b/src/generated/resources/data/c/tags/items/skulls.json @@ -0,0 +1,11 @@ +{ + "replace": false, + "values": [ + "minecraft:creeper_head", + "minecraft:dragon_head", + "minecraft:player_head", + "minecraft:skeleton_skull", + "minecraft:wither_skeleton_skull", + "minecraft:zombie_head" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/items/stones.json b/src/generated/resources/data/c/tags/items/stones.json new file mode 100644 index 000000000..f336e9826 --- /dev/null +++ b/src/generated/resources/data/c/tags/items/stones.json @@ -0,0 +1,17 @@ +{ + "replace": false, + "values": [ + "minecraft:andesite", + "minecraft:diorite", + "minecraft:granite", + "minecraft:infested_stone", + "minecraft:stone", + "minecraft:polished_andesite", + "minecraft:polished_diorite", + "minecraft:polished_granite", + "minecraft:deepslate", + "minecraft:polished_deepslate", + "minecraft:infested_deepslate", + "minecraft:tuff" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/items/wooden_chests.json b/src/generated/resources/data/c/tags/items/wooden_chests.json new file mode 100644 index 000000000..441d80f5b --- /dev/null +++ b/src/generated/resources/data/c/tags/items/wooden_chests.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:chest", + "minecraft:trapped_chest" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/cable.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/cable.json new file mode 100644 index 000000000..ecec5122c --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/cable.json @@ -0,0 +1,43 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:cable" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_modem": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:wired_modem" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:cable" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_modem", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json new file mode 100644 index 000000000..99eeaf6f2 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:computer_advanced" + ] + }, + "criteria": { + "has_components": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:redstone" + ] + }, + { + "items": [ + "minecraft:gold_ingot" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:computer_advanced" + } + } + }, + "requirements": [ + [ + "has_components", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json new file mode 100644 index 000000000..9ea24782f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:computer_command" + ] + }, + "criteria": { + "has_components": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:command_block" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:computer_command" + } + } + }, + "requirements": [ + [ + "has_components", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json new file mode 100644 index 000000000..4f4893931 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:computer_normal" + ] + }, + "criteria": { + "has_redstone": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "c:redstone_dusts" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:computer_normal" + } + } + }, + "requirements": [ + [ + "has_redstone", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json new file mode 100644 index 000000000..9f34f0132 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_1" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_1" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json new file mode 100644 index 000000000..00b6063f7 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_10" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_10" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json new file mode 100644 index 000000000..38561cda0 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_11" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_11" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json new file mode 100644 index 000000000..e88addd4f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_12" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_12" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json new file mode 100644 index 000000000..cd19ae33f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_13" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_13" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json new file mode 100644 index 000000000..ef0f17843 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_14" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_14" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json new file mode 100644 index 000000000..678d48d21 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_15" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_15" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json new file mode 100644 index 000000000..f5d5d597a --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_16" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_16" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json new file mode 100644 index 000000000..089eefa55 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_2" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_2" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json new file mode 100644 index 000000000..01ba3291e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_3" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_3" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json new file mode 100644 index 000000000..f9fb5a70e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_4" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_4" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json new file mode 100644 index 000000000..d0d8b138e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_5" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_5" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json new file mode 100644 index 000000000..d8c18541f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_6" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_6" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json new file mode 100644 index 000000000..1d4936bf6 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_7" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_7" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json new file mode 100644 index 000000000..dac96a1f1 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_8" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_8" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json new file mode 100644 index 000000000..bcb7a3b4f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_9" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:disk_drive" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_9" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json new file mode 100644 index 000000000..7fb18766e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_drive" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_drive" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json new file mode 100644 index 000000000..dab4faad3 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:monitor_advanced" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:monitor_advanced" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json new file mode 100644 index 000000000..fdd3c274c --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:monitor_normal" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:monitor_normal" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json new file mode 100644 index 000000000..90a8720e5 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/computercraft/speaker" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:pocket_computer_advanced" + ] + }, + { + "items": [ + "computercraft:speaker" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/computercraft/speaker" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..d2c68d9c2 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/computercraft/wireless_modem_advanced" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:pocket_computer_advanced" + ] + }, + { + "items": [ + "computercraft:wireless_modem_advanced" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/computercraft/wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..c43257316 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/computercraft/wireless_modem_normal" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:pocket_computer_advanced" + ] + }, + { + "items": [ + "computercraft:wireless_modem_normal" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/computercraft/wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json new file mode 100644 index 000000000..7fba02295 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json @@ -0,0 +1,45 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_computer_advanced" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_apple": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:golden_apple" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_computer_advanced" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_apple", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json new file mode 100644 index 000000000..5a775c486 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json @@ -0,0 +1,45 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_computer_normal" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_apple": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:golden_apple" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_computer_normal" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_apple", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json new file mode 100644 index 000000000..c7f1206aa --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/computercraft/speaker" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:pocket_computer_normal" + ] + }, + { + "items": [ + "computercraft:speaker" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/computercraft/speaker" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..ece1617c1 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/computercraft/wireless_modem_advanced" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:pocket_computer_normal" + ] + }, + { + "items": [ + "computercraft:wireless_modem_advanced" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/computercraft/wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..bef52186e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/computercraft/wireless_modem_normal" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:pocket_computer_normal" + ] + }, + { + "items": [ + "computercraft:wireless_modem_normal" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/computercraft/wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printed_book.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printed_book.json new file mode 100644 index 000000000..5435f8029 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printed_book.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:printed_book" + ] + }, + "criteria": { + "has_printer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:printer" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:printed_book" + } + } + }, + "requirements": [ + [ + "has_printer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printed_pages.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printed_pages.json new file mode 100644 index 000000000..c02672917 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printed_pages.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:printed_pages" + ] + }, + "criteria": { + "has_printer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:printer" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:printed_pages" + } + } + }, + "requirements": [ + [ + "has_printer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printer.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printer.json new file mode 100644 index 000000000..08a2ffeba --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printer.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:printer" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:printer" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/speaker.json new file mode 100644 index 000000000..194f7caec --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/speaker.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:speaker" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:speaker" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json new file mode 100644 index 000000000..c54721424 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/computercraft/speaker" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "computercraft:speaker" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/computercraft/speaker" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..66ee37549 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/computercraft/wireless_modem_advanced" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "computercraft:wireless_modem_advanced" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/computercraft/wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..ae2c6c4ab --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/computercraft/wireless_modem_normal" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "computercraft:wireless_modem_normal" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/computercraft/wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json new file mode 100644 index 000000000..39187358f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/crafting_table" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "minecraft:crafting_table" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/crafting_table" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json new file mode 100644 index 000000000..e026aaf7e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_axe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "minecraft:diamond_axe" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_axe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json new file mode 100644 index 000000000..22c965bb3 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_hoe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "minecraft:diamond_hoe" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_hoe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..796b0cae0 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_pickaxe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "minecraft:diamond_pickaxe" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_pickaxe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json new file mode 100644 index 000000000..6f5105d04 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_shovel" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "minecraft:diamond_shovel" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_shovel" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json new file mode 100644 index 000000000..feaaa0562 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_sword" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "minecraft:diamond_sword" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_sword" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/netherite_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/netherite_pickaxe.json new file mode 100644 index 000000000..d5a841501 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/netherite_pickaxe.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/netherite_pickaxe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_advanced" + ] + }, + { + "items": [ + "minecraft:netherite_pickaxe" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/netherite_pickaxe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json new file mode 100644 index 000000000..9580aa6c1 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/computercraft/speaker" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "computercraft:speaker" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/computercraft/speaker" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..7b26f6f86 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/computercraft/wireless_modem_advanced" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "computercraft:wireless_modem_advanced" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/computercraft/wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..3e1817136 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/computercraft/wireless_modem_normal" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "computercraft:wireless_modem_normal" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/computercraft/wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json new file mode 100644 index 000000000..a499c785c --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/crafting_table" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "minecraft:crafting_table" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/crafting_table" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json new file mode 100644 index 000000000..3b3218736 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_axe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "minecraft:diamond_axe" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_axe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json new file mode 100644 index 000000000..898fb3b0f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_hoe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "minecraft:diamond_hoe" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_hoe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..3ec2cbd33 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_pickaxe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "minecraft:diamond_pickaxe" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_pickaxe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json new file mode 100644 index 000000000..5991f2b95 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_shovel" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "minecraft:diamond_shovel" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_shovel" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json new file mode 100644 index 000000000..1e4db9448 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_sword" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "minecraft:diamond_sword" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_sword" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/netherite_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/netherite_pickaxe.json new file mode 100644 index 000000000..4c586b2aa --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/netherite_pickaxe.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/netherite_pickaxe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:turtle_normal" + ] + }, + { + "items": [ + "minecraft:netherite_pickaxe" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/netherite_pickaxe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json new file mode 100644 index 000000000..861de293d --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json @@ -0,0 +1,45 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wired_modem" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_cable": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:cable" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wired_modem" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_cable", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json new file mode 100644 index 000000000..a54c82034 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wired_modem_full_from" + ] + }, + "criteria": { + "has_modem": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:wired_modem" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wired_modem_full_from" + } + } + }, + "requirements": [ + [ + "has_modem", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json new file mode 100644 index 000000000..c0eaec110 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wired_modem_full_to" + ] + }, + "criteria": { + "has_modem": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:wired_modem" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wired_modem_full_to" + } + } + }, + "requirements": [ + [ + "has_modem", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..4b738939f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json @@ -0,0 +1,45 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wireless_modem_advanced" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_wireless": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:wireless_modem_normal" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_wireless", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..b0ce1c994 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wireless_modem_normal" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_cloudy.json b/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_cloudy.json new file mode 100644 index 000000000..d6b316cee --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_cloudy.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:skull_cloudy" + ] + }, + "criteria": { + "has_monitor": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:monitor_normal" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:skull_cloudy" + } + } + }, + "requirements": [ + [ + "has_monitor", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_dan200.json b/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_dan200.json new file mode 100644 index 000000000..168c59893 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/decorations/skull_dan200.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:skull_dan200" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "computercraft:computer_normal" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:skull_dan200" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/cable.json b/src/generated/resources/data/computercraft/loot_tables/blocks/cable.json new file mode 100644 index 000000000..7addfe9db --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/cable.json @@ -0,0 +1,52 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:cable" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + }, + { + "condition": "minecraft:block_state_property", + "block": "computercraft:cable", + "properties": { + "cable": "true" + } + } + ] + }, + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:wired_modem" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "minecraft:block_state_property", + "block": "computercraft:cable", + "properties": { + "modem": "none" + } + } + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json new file mode 100644 index 000000000..cdf402d03 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json @@ -0,0 +1,34 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "computercraft:has_id" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json new file mode 100644 index 000000000..cdf402d03 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json @@ -0,0 +1,34 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "computercraft:has_id" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json new file mode 100644 index 000000000..cdf402d03 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json @@ -0,0 +1,34 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "computercraft:has_id" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/disk_drive.json b/src/generated/resources/data/computercraft/loot_tables/blocks/disk_drive.json new file mode 100644 index 000000000..06c4e84e5 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/disk_drive.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:disk_drive" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json new file mode 100644 index 000000000..8df3e7df6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:monitor_advanced" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_normal.json new file mode 100644 index 000000000..d190321ba --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_normal.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:monitor_normal" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/printer.json b/src/generated/resources/data/computercraft/loot_tables/blocks/printer.json new file mode 100644 index 000000000..6d4f43ee8 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/printer.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:printer" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/speaker.json b/src/generated/resources/data/computercraft/loot_tables/blocks/speaker.json new file mode 100644 index 000000000..d3323bde2 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/speaker.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:speaker" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json new file mode 100644 index 000000000..cdf402d03 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json @@ -0,0 +1,34 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "computercraft:has_id" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json new file mode 100644 index 000000000..cdf402d03 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json @@ -0,0 +1,34 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "computercraft:has_id" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json b/src/generated/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json new file mode 100644 index 000000000..7ba86d6d6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:wired_modem_full" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json new file mode 100644 index 000000000..3e2daf5e5 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:wireless_modem_advanced" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json new file mode 100644 index 000000000..0fba46907 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:wireless_modem_normal" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/cable.json b/src/generated/resources/data/computercraft/recipes/cable.json new file mode 100644 index 000000000..02911c183 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/cable.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " # ", + "#R#", + " # " + ], + "key": { + "#": { + "tag": "c:stones" + }, + "R": { + "tag": "c:redstone_dusts" + } + }, + "result": { + "item": "computercraft:cable", + "count": 6 + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/colour.json b/src/generated/resources/data/computercraft/recipes/colour.json new file mode 100644 index 000000000..f8e494be2 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/colour.json @@ -0,0 +1,3 @@ +{ + "type": "computercraft:colour" +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/computer_advanced.json b/src/generated/resources/data/computercraft/recipes/computer_advanced.json new file mode 100644 index 000000000..b638062fd --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/computer_advanced.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#G#" + ], + "key": { + "#": { + "tag": "c:gold_ingots" + }, + "R": { + "tag": "c:redstone_dusts" + }, + "G": { + "tag": "c:glass_panes" + } + }, + "result": { + "item": "computercraft:computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/computer_command.json b/src/generated/resources/data/computercraft/recipes/computer_command.json new file mode 100644 index 000000000..e9db75032 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/computer_command.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#G#" + ], + "key": { + "#": { + "tag": "c:gold_ingots" + }, + "R": { + "item": "minecraft:command_block" + }, + "G": { + "tag": "c:glass_panes" + } + }, + "result": { + "item": "computercraft:computer_command" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/computer_normal.json b/src/generated/resources/data/computercraft/recipes/computer_normal.json new file mode 100644 index 000000000..94c923635 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/computer_normal.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#G#" + ], + "key": { + "#": { + "tag": "c:stones" + }, + "R": { + "tag": "c:redstone_dusts" + }, + "G": { + "tag": "c:glass_panes" + } + }, + "result": { + "item": "computercraft:computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk.json b/src/generated/resources/data/computercraft/recipes/disk.json new file mode 100644 index 000000000..32c3a567d --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk.json @@ -0,0 +1,3 @@ +{ + "type": "computercraft:disk" +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_1.json b/src/generated/resources/data/computercraft/recipes/disk_1.json new file mode 100644 index 000000000..bc8902480 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_1.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:black_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:1118481}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_10.json b/src/generated/resources/data/computercraft/recipes/disk_10.json new file mode 100644 index 000000000..2b880c729 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_10.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:pink_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:15905484}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_11.json b/src/generated/resources/data/computercraft/recipes/disk_11.json new file mode 100644 index 000000000..0bccf8ac8 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_11.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:lime_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:8375321}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_12.json b/src/generated/resources/data/computercraft/recipes/disk_12.json new file mode 100644 index 000000000..e41b90738 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_12.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:yellow_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:14605932}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_13.json b/src/generated/resources/data/computercraft/recipes/disk_13.json new file mode 100644 index 000000000..f48085a58 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_13.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:light_blue_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:10072818}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_14.json b/src/generated/resources/data/computercraft/recipes/disk_14.json new file mode 100644 index 000000000..b7fd2108a --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_14.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:magenta_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:15040472}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_15.json b/src/generated/resources/data/computercraft/recipes/disk_15.json new file mode 100644 index 000000000..fd383fe64 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_15.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:orange_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:15905331}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_16.json b/src/generated/resources/data/computercraft/recipes/disk_16.json new file mode 100644 index 000000000..5b4fca9dd --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_16.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:white_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:15790320}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_2.json b/src/generated/resources/data/computercraft/recipes/disk_2.json new file mode 100644 index 000000000..958f09cf6 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_2.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:red_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:13388876}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_3.json b/src/generated/resources/data/computercraft/recipes/disk_3.json new file mode 100644 index 000000000..2299521ac --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_3.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:green_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:5744206}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_4.json b/src/generated/resources/data/computercraft/recipes/disk_4.json new file mode 100644 index 000000000..af928981e --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_4.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:brown_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:8349260}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_5.json b/src/generated/resources/data/computercraft/recipes/disk_5.json new file mode 100644 index 000000000..e25cf0ffa --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_5.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:blue_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:3368652}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_6.json b/src/generated/resources/data/computercraft/recipes/disk_6.json new file mode 100644 index 000000000..270735db3 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_6.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:purple_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:11691749}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_7.json b/src/generated/resources/data/computercraft/recipes/disk_7.json new file mode 100644 index 000000000..fef7cef21 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_7.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:cyan_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:5020082}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_8.json b/src/generated/resources/data/computercraft/recipes/disk_8.json new file mode 100644 index 000000000..ba3d26d55 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_8.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:light_gray_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:10066329}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_9.json b/src/generated/resources/data/computercraft/recipes/disk_9.json new file mode 100644 index 000000000..61eab3de4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_9.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "c:redstone_dusts" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:gray_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{Color:5000268}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_drive.json b/src/generated/resources/data/computercraft/recipes/disk_drive.json new file mode 100644 index 000000000..6a5e0a277 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_drive.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#R#" + ], + "key": { + "#": { + "tag": "c:stones" + }, + "R": { + "tag": "c:redstone_dusts" + } + }, + "result": { + "item": "computercraft:disk_drive" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/monitor_advanced.json b/src/generated/resources/data/computercraft/recipes/monitor_advanced.json new file mode 100644 index 000000000..67d086c50 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/monitor_advanced.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#G#", + "###" + ], + "key": { + "#": { + "tag": "c:gold_ingots" + }, + "G": { + "tag": "c:glass_panes" + } + }, + "result": { + "item": "computercraft:monitor_advanced", + "count": 4 + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/monitor_normal.json b/src/generated/resources/data/computercraft/recipes/monitor_normal.json new file mode 100644 index 000000000..72e2ec884 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/monitor_normal.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#G#", + "###" + ], + "key": { + "#": { + "tag": "c:stones" + }, + "G": { + "tag": "c:glass_panes" + } + }, + "result": { + "item": "computercraft:monitor_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json new file mode 100644 index 000000000..567e5aea4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json @@ -0,0 +1,20 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "P": { + "item": "computercraft:pocket_computer_advanced" + }, + "#": { + "item": "computercraft:speaker" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced", + "nbt": "{Upgrade:\"computercraft:speaker\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..222c93ae6 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,20 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "P": { + "item": "computercraft:pocket_computer_advanced" + }, + "#": { + "item": "computercraft:wireless_modem_advanced" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced", + "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..cd9ff2d17 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,20 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "P": { + "item": "computercraft:pocket_computer_advanced" + }, + "#": { + "item": "computercraft:wireless_modem_normal" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced", + "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json b/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json new file mode 100644 index 000000000..3756b4a7c --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#A#", + "#G#" + ], + "key": { + "#": { + "tag": "c:gold_ingots" + }, + "A": { + "item": "minecraft:golden_apple" + }, + "G": { + "tag": "c:glass_panes" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json b/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json new file mode 100644 index 000000000..66e2a44ba --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#A#", + "#G#" + ], + "key": { + "#": { + "tag": "c:stones" + }, + "A": { + "item": "minecraft:golden_apple" + }, + "G": { + "tag": "c:glass_panes" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_computer_upgrade.json b/src/generated/resources/data/computercraft/recipes/pocket_computer_upgrade.json new file mode 100644 index 000000000..22fdf4c40 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_computer_upgrade.json @@ -0,0 +1,3 @@ +{ + "type": "computercraft:pocket_computer_upgrade" +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json new file mode 100644 index 000000000..dc388cbd4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json @@ -0,0 +1,20 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "P": { + "item": "computercraft:pocket_computer_normal" + }, + "#": { + "item": "computercraft:speaker" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal", + "nbt": "{Upgrade:\"computercraft:speaker\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..c1e7ef083 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,20 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "P": { + "item": "computercraft:pocket_computer_normal" + }, + "#": { + "item": "computercraft:wireless_modem_advanced" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal", + "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..bf12b0174 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,20 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "P": { + "item": "computercraft:pocket_computer_normal" + }, + "#": { + "item": "computercraft:wireless_modem_normal" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal", + "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/printed_book.json b/src/generated/resources/data/computercraft/recipes/printed_book.json new file mode 100644 index 000000000..e86e66703 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/printed_book.json @@ -0,0 +1,17 @@ +{ + "type": "computercraft:impostor_shapeless", + "ingredients": [ + { + "item": "minecraft:leather" + }, + { + "item": "computercraft:printed_page" + }, + { + "item": "minecraft:string" + } + ], + "result": { + "item": "computercraft:printed_book" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/printed_pages.json b/src/generated/resources/data/computercraft/recipes/printed_pages.json new file mode 100644 index 000000000..10e045136 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/printed_pages.json @@ -0,0 +1,17 @@ +{ + "type": "computercraft:impostor_shapeless", + "ingredients": [ + { + "item": "computercraft:printed_page" + }, + { + "item": "computercraft:printed_page" + }, + { + "item": "minecraft:string" + } + ], + "result": { + "item": "computercraft:printed_pages" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/printer.json b/src/generated/resources/data/computercraft/recipes/printer.json new file mode 100644 index 000000000..fe6a01999 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/printer.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#D#" + ], + "key": { + "#": { + "tag": "c:stones" + }, + "R": { + "tag": "c:redstone_dusts" + }, + "D": { + "tag": "c:dyes" + } + }, + "result": { + "item": "computercraft:printer" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/printout.json b/src/generated/resources/data/computercraft/recipes/printout.json new file mode 100644 index 000000000..0e1a02157 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/printout.json @@ -0,0 +1,3 @@ +{ + "type": "computercraft:printout" +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/skull_cloudy.json b/src/generated/resources/data/computercraft/recipes/skull_cloudy.json new file mode 100644 index 000000000..97c489734 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/skull_cloudy.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "tag": "c:skulls" + }, + { + "item": "computercraft:monitor_normal" + } + ], + "result": { + "item": "minecraft:player_head", + "nbt": "{SkullOwner:{Id:\"6d074736-b1e9-4378-a99b-bd8777821c9c\",Name:\"Cloudhunter\"}}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/skull_dan200.json b/src/generated/resources/data/computercraft/recipes/skull_dan200.json new file mode 100644 index 000000000..8519822bf --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/skull_dan200.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "tag": "c:skulls" + }, + { + "item": "computercraft:computer_normal" + } + ], + "result": { + "item": "minecraft:player_head", + "nbt": "{SkullOwner:{Id:\"f3c8d69b-0776-4512-8434-d1b2165909eb\",Name:\"dan200\"}}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/speaker.json b/src/generated/resources/data/computercraft/recipes/speaker.json new file mode 100644 index 000000000..12259140d --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/speaker.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#N#", + "#R#" + ], + "key": { + "#": { + "tag": "c:stones" + }, + "N": { + "item": "minecraft:note_block" + }, + "R": { + "tag": "c:redstone_dusts" + } + }, + "result": { + "item": "computercraft:speaker" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json new file mode 100644 index 000000000..2cf9964a2 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "computercraft:speaker" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"computercraft:speaker\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..c6cc910fe --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "computercraft:wireless_modem_advanced" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..7451f115f --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "computercraft:wireless_modem_normal" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json new file mode 100644 index 000000000..15d1993bf --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "minecraft:crafting_table" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:crafting_table\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json new file mode 100644 index 000000000..774438beb --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "minecraft:diamond_axe" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_axe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json new file mode 100644 index 000000000..cf00c7587 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "minecraft:diamond_hoe" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..58560f66c --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "minecraft:diamond_pickaxe" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json new file mode 100644 index 000000000..614e6178f --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "minecraft:diamond_shovel" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json new file mode 100644 index 000000000..846b6bc8e --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "minecraft:diamond_sword" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_sword\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/netherite_pickaxe.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/netherite_pickaxe.json new file mode 100644 index 000000000..fcfe66888 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/netherite_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_advanced" + }, + "#": { + "item": "minecraft:netherite_pickaxe" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:netherite_pickaxe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json new file mode 100644 index 000000000..39e3fa7e8 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "computercraft:speaker" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"computercraft:speaker\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..7b6da28e4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "computercraft:wireless_modem_advanced" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..66d096584 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "computercraft:wireless_modem_normal" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json new file mode 100644 index 000000000..31647e842 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "minecraft:crafting_table" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:crafting_table\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json new file mode 100644 index 000000000..a79534db6 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "minecraft:diamond_axe" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_axe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json new file mode 100644 index 000000000..0c0fc1c39 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "minecraft:diamond_hoe" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..0490a1267 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "minecraft:diamond_pickaxe" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json new file mode 100644 index 000000000..7bbe87284 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "minecraft:diamond_shovel" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json new file mode 100644 index 000000000..ba893dc67 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "minecraft:diamond_sword" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_sword\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/netherite_pickaxe.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/netherite_pickaxe.json new file mode 100644 index 000000000..750320508 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/netherite_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "T": { + "item": "computercraft:turtle_normal" + }, + "#": { + "item": "minecraft:netherite_pickaxe" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:netherite_pickaxe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_upgrade.json b/src/generated/resources/data/computercraft/recipes/turtle_upgrade.json new file mode 100644 index 000000000..62e103b60 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_upgrade.json @@ -0,0 +1,3 @@ +{ + "type": "computercraft:turtle_upgrade" +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wired_modem.json b/src/generated/resources/data/computercraft/recipes/wired_modem.json new file mode 100644 index 000000000..08290b43a --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wired_modem.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "###" + ], + "key": { + "#": { + "tag": "c:stones" + }, + "R": { + "tag": "c:redstone_dusts" + } + }, + "result": { + "item": "computercraft:wired_modem" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json b/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json new file mode 100644 index 000000000..7865f45de --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "computercraft:wired_modem" + } + ], + "result": { + "item": "computercraft:wired_modem_full" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json b/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json new file mode 100644 index 000000000..8c303ebb4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "computercraft:wired_modem_full" + } + ], + "result": { + "item": "computercraft:wired_modem" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json new file mode 100644 index 000000000..1682913f8 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#E#", + "###" + ], + "key": { + "#": { + "tag": "c:gold_ingots" + }, + "E": { + "item": "minecraft:ender_eye" + } + }, + "result": { + "item": "computercraft:wireless_modem_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json new file mode 100644 index 000000000..4e5539a8f --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#E#", + "###" + ], + "key": { + "#": { + "tag": "c:stones" + }, + "E": { + "tag": "c:ender_pearls" + } + }, + "result": { + "item": "computercraft:wireless_modem_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/blocks/computer.json b/src/generated/resources/data/computercraft/tags/blocks/computer.json new file mode 100644 index 000000000..bcd0e8037 --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/blocks/computer.json @@ -0,0 +1,8 @@ +{ + "replace": false, + "values": [ + "computercraft:computer_normal", + "computercraft:computer_advanced", + "computercraft:computer_command" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/blocks/monitor.json b/src/generated/resources/data/computercraft/tags/blocks/monitor.json new file mode 100644 index 000000000..babaefa8b --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/blocks/monitor.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "computercraft:monitor_normal", + "computercraft:monitor_advanced" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/blocks/turtle.json b/src/generated/resources/data/computercraft/tags/blocks/turtle.json new file mode 100644 index 000000000..e4277edfe --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/blocks/turtle.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "computercraft:turtle_normal", + "computercraft:turtle_advanced" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/computercraft/tags/blocks/turtle_always_breakable.json b/src/generated/resources/data/computercraft/tags/blocks/turtle_always_breakable.json similarity index 98% rename from src/main/resources/data/computercraft/tags/blocks/turtle_always_breakable.json rename to src/generated/resources/data/computercraft/tags/blocks/turtle_always_breakable.json index c4225f023..1d795dcef 100644 --- a/src/main/resources/data/computercraft/tags/blocks/turtle_always_breakable.json +++ b/src/generated/resources/data/computercraft/tags/blocks/turtle_always_breakable.json @@ -5,4 +5,4 @@ "minecraft:bamboo", "minecraft:bamboo_sapling" ] -} +} \ No newline at end of file diff --git a/src/main/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json b/src/generated/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json similarity index 99% rename from src/main/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json rename to src/generated/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json index 6f687aeb6..10e786424 100644 --- a/src/main/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json +++ b/src/generated/resources/data/computercraft/tags/blocks/turtle_hoe_harvestable.json @@ -9,4 +9,4 @@ "minecraft:carved_pumpkin", "minecraft:jack_o_lantern" ] -} +} \ No newline at end of file diff --git a/src/main/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json b/src/generated/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json similarity index 98% rename from src/main/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json rename to src/generated/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json index 06ba799d8..f6a10bb7f 100644 --- a/src/main/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json +++ b/src/generated/resources/data/computercraft/tags/blocks/turtle_shovel_harvestable.json @@ -7,4 +7,4 @@ "minecraft:carved_pumpkin", "minecraft:jack_o_lantern" ] -} +} \ No newline at end of file diff --git a/src/main/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json b/src/generated/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json similarity index 97% rename from src/main/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json rename to src/generated/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json index 931423b91..c38f1efd8 100644 --- a/src/main/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json +++ b/src/generated/resources/data/computercraft/tags/blocks/turtle_sword_harvestable.json @@ -4,4 +4,4 @@ "#minecraft:wool", "minecraft:cobweb" ] -} +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/blocks/wired_modem.json b/src/generated/resources/data/computercraft/tags/blocks/wired_modem.json new file mode 100644 index 000000000..10ade37b3 --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/blocks/wired_modem.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "computercraft:cable", + "computercraft:wired_modem_full" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/items/computer.json b/src/generated/resources/data/computercraft/tags/items/computer.json new file mode 100644 index 000000000..bcd0e8037 --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/items/computer.json @@ -0,0 +1,8 @@ +{ + "replace": false, + "values": [ + "computercraft:computer_normal", + "computercraft:computer_advanced", + "computercraft:computer_command" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/items/monitor.json b/src/generated/resources/data/computercraft/tags/items/monitor.json new file mode 100644 index 000000000..babaefa8b --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/items/monitor.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "computercraft:monitor_normal", + "computercraft:monitor_advanced" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/items/turtle.json b/src/generated/resources/data/computercraft/tags/items/turtle.json new file mode 100644 index 000000000..e4277edfe --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/items/turtle.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "computercraft:turtle_normal", + "computercraft:turtle_advanced" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/items/wired_modem.json b/src/generated/resources/data/computercraft/tags/items/wired_modem.json new file mode 100644 index 000000000..57db1557f --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/items/wired_modem.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "computercraft:wired_modem", + "computercraft:wired_modem_full" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json new file mode 100644 index 000000000..bb1e60dbc --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -0,0 +1,18 @@ +{ + "replace": false, + "values": [ + "computercraft:computer_normal", + "computercraft:computer_advanced", + "computercraft:turtle_normal", + "computercraft:turtle_advanced", + "computercraft:speaker", + "computercraft:disk_drive", + "computercraft:printer", + "computercraft:monitor_normal", + "computercraft:monitor_advanced", + "computercraft:wireless_modem_normal", + "computercraft:wireless_modem_advanced", + "computercraft:wired_modem_full", + "computercraft:cable" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/minecraft/tags/items/piglin_loved.json b/src/generated/resources/data/minecraft/tags/items/piglin_loved.json similarity index 99% rename from src/main/resources/data/minecraft/tags/items/piglin_loved.json rename to src/generated/resources/data/minecraft/tags/items/piglin_loved.json index 534e2a988..8eedcc427 100644 --- a/src/main/resources/data/minecraft/tags/items/piglin_loved.json +++ b/src/generated/resources/data/minecraft/tags/items/piglin_loved.json @@ -7,4 +7,4 @@ "computercraft:pocket_computer_advanced", "computercraft:monitor_advanced" ] -} +} \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 93e8afacd..e977120c5 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -7,7 +7,6 @@ import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.AddressRule; -import dan200.computercraft.shared.Registry.ModBlocks; import dan200.computercraft.shared.common.ColourableRecipe; import dan200.computercraft.shared.computer.core.ClientComputerRegistry; import dan200.computercraft.shared.computer.core.ServerComputerRegistry; @@ -24,15 +23,11 @@ import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; import dan200.computercraft.shared.util.ImpostorRecipe; import dan200.computercraft.shared.util.ImpostorShapelessRecipe; -import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.ResourcePackActivationType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.ItemStack; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -41,7 +36,7 @@ import static dan200.computercraft.shared.Registry.init; -public final class ComputerCraft implements ModInitializer +public final class ComputerCraft { public static final String MOD_ID = "computercraft"; @@ -104,10 +99,7 @@ public final class ComputerCraft implements ModInitializer // Logging public static final Logger log = LogManager.getLogger( MOD_ID ); - public static CreativeModeTab MAIN_GROUP = FabricItemGroupBuilder.build( new ResourceLocation( MOD_ID, "main" ), () -> new ItemStack( ModBlocks.COMPUTER_NORMAL ) ); - - @Override - public void onInitialize() + public static void onInitialize() { ComputerCraftProxyCommon.init(); Registry.register( Registry.RECIPE_SERIALIZER, new ResourceLocation( ComputerCraft.MOD_ID, "colour" ), ColourableRecipe.SERIALIZER ); diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 11791d4cf..3c4e0e75b 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -283,6 +283,7 @@ public interface IComputerCraftAPI int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ); void registerMediaProvider( @Nonnull IMediaProvider provider ); + @Nonnull IPacketNetwork getWirelessNetwork(); diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java index 460ace58f..c9dcfeda9 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java @@ -6,8 +6,8 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.ComputerCraftAPI; -import dan200.computercraft.api.upgrades.IUpgradeBase; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.upgrades.IUpgradeBase; import net.minecraft.world.level.Level; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index 260a2aff7..51c3f2dad 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -6,9 +6,9 @@ package dan200.computercraft.api.turtle; import dan200.computercraft.api.ComputerCraftAPI; -import dan200.computercraft.api.upgrades.IUpgradeBase; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.upgrades.IUpgradeBase; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.core.Direction; diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java deleted file mode 100644 index 5e82c7091..000000000 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.client.gui; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Matrix3f; -import com.mojang.math.Matrix4f; -import dan200.computercraft.client.FrameInfo; -import dan200.computercraft.client.render.RenderTypes; -import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.core.terminal.TextBuffer; -import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.Palette; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.texture.OverlayTexture; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; - -/** - * Handles rendering fixed width text and computer terminals. - * - * This class has several modes of usage: - * - */ -public final class FixedWidthFontRenderer -{ - public static final int FONT_HEIGHT = 9; - public static final int FONT_WIDTH = 6; - public static final float WIDTH = 256.0f; - - public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; - public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; - - public static final float Z_EPSILON = 0.001f; - - private FixedWidthFontRenderer() - { - } - - public static float toGreyscale( double[] rgb ) - { - return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); - } - - public static int getColour( char c, Colour def ) - { - return 15 - Terminal.getColour( c, def ); - } - - private static void drawChar( PoseStack transform, VertexConsumer buffer, float x, float y, int index, float r, float g, float b, int light ) - { - // Short circuit to avoid the common case - the texture should be blank here after all. - if( index == '\0' || index == ' ' ) return; - - int column = index % 16; - int row = index / 16; - - int xStart = 1 + column * (FONT_WIDTH + 2); - int yStart = 1 + row * (FONT_HEIGHT + 2); - - Matrix4f matrix = transform.last().pose(); - Matrix3f normalMatrix = transform.last().normal(); - vertex( matrix, normalMatrix, buffer, x, y, Z_EPSILON, r, g, b, xStart / WIDTH, yStart / WIDTH, light ); - vertex( matrix, normalMatrix, buffer, x, y + FONT_HEIGHT, Z_EPSILON, r, g, b, xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH, light ); - vertex( matrix, normalMatrix, buffer, x + FONT_WIDTH, y + FONT_HEIGHT, Z_EPSILON, r, g, b, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH, light ); - vertex( matrix, normalMatrix, buffer, x + FONT_WIDTH, y, Z_EPSILON, r, g, b, (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH, light ); - } - - private static void drawQuad( PoseStack transform, VertexConsumer buffer, float x, float y, float width, float height, float r, float g, float b, int light ) - { - Matrix4f matrix = transform.last().pose(); - Matrix3f normalMatrix = transform.last().normal(); - vertex( matrix, normalMatrix, buffer, x, y, 0, r, g, b, BACKGROUND_START, BACKGROUND_START, light ); - vertex( matrix, normalMatrix, buffer, x, y + height, 0, r, g, b, BACKGROUND_START, BACKGROUND_END, light ); - vertex( matrix, normalMatrix, buffer, x + width, y + height, 0, r, g, b, BACKGROUND_END, BACKGROUND_END, light ); - vertex( matrix, normalMatrix, buffer, x + width, y, 0, r, g, b, BACKGROUND_END, BACKGROUND_START, light ); - } - - private static void drawQuad( PoseStack transform, VertexConsumer buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex, int light ) - { - double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) ); - float r, g, b; - if( greyscale ) - { - r = g = b = toGreyscale( colour ); - } - else - { - r = (float) colour[0]; - g = (float) colour[1]; - b = (float) colour[2]; - } - - drawQuad( transform, buffer, x, y, width, height, r, g, b, light ); - } - - private static void drawBackground( - @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, float x, float y, - @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, - float leftMarginSize, float rightMarginSize, float height, int light - ) - { - if( leftMarginSize > 0 ) - { - drawQuad( transform, buffer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ), light ); - } - - if( rightMarginSize > 0 ) - { - drawQuad( transform, buffer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ), light ); - } - - // Batch together runs of identical background cells. - int blockStart = 0; - char blockColour = '\0'; - for( int i = 0; i < backgroundColour.length(); i++ ) - { - char colourIndex = backgroundColour.charAt( i ); - if( colourIndex == blockColour ) continue; - - if( blockColour != '\0' ) - { - drawQuad( transform, buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour, light ); - } - - blockColour = colourIndex; - blockStart = i; - } - - if( blockColour != '\0' ) - { - drawQuad( transform, buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour, light ); - } - } - - public static void drawString( - @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, float x, float y, - @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, - @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize, int light - ) - { - if( backgroundColour != null ) - { - drawBackground( transform, buffer, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT, light ); - } - - for( int i = 0; i < text.length(); i++ ) - { - double[] colour = palette.getColour( getColour( textColour.charAt( i ), Colour.BLACK ) ); - float r, g, b; - if( greyscale ) - { - r = g = b = toGreyscale( colour ); - } - else - { - r = (float) colour[0]; - g = (float) colour[1]; - b = (float) colour[2]; - } - - // Draw char - int index = text.charAt( i ); - if( index > 255 ) index = '?'; - drawChar( transform, buffer, x + i * FONT_WIDTH, y, index, r, g, b, light ); - } - - } - - public static void drawTerminalWithoutCursor( - @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, float x, float y, - @Nonnull Terminal terminal, boolean greyscale, - float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize, int light - ) - { - Palette palette = terminal.getPalette(); - int height = terminal.getHeight(); - - // Top and bottom margins - drawBackground( - transform, buffer, x, y - topMarginSize, - terminal.getBackgroundColourLine( 0 ), palette, greyscale, - leftMarginSize, rightMarginSize, topMarginSize, light - ); - - drawBackground( - transform, buffer, x, y + height * FONT_HEIGHT, - terminal.getBackgroundColourLine( height - 1 ), palette, greyscale, - leftMarginSize, rightMarginSize, bottomMarginSize, light - ); - - // The main text - for( int i = 0; i < height; i++ ) - { - drawString( - transform, buffer, x, y + FixedWidthFontRenderer.FONT_HEIGHT * i, - terminal.getLine( i ), terminal.getTextColourLine( i ), terminal.getBackgroundColourLine( i ), - palette, greyscale, leftMarginSize, rightMarginSize, FULL_BRIGHT_LIGHTMAP - ); - } - } - - public static void drawCursor( - @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, float x, float y, - @Nonnull Terminal terminal, boolean greyscale - ) - { - Palette palette = terminal.getPalette(); - int width = terminal.getWidth(); - int height = terminal.getHeight(); - - int cursorX = terminal.getCursorX(); - int cursorY = terminal.getCursorY(); - if( terminal.getCursorBlink() && cursorX >= 0 && cursorX < width && cursorY >= 0 && cursorY < height && FrameInfo.getGlobalCursorBlink() ) - { - double[] colour = palette.getColour( 15 - terminal.getTextColour() ); - float r, g, b; - if( greyscale ) - { - r = g = b = toGreyscale( colour ); - } - else - { - r = (float) colour[0]; - g = (float) colour[1]; - b = (float) colour[2]; - } - - drawChar( transform, buffer, x + cursorX * FONT_WIDTH, y + cursorY * FONT_HEIGHT, '_', r, g, b, FULL_BRIGHT_LIGHTMAP ); - } - } - - public static void drawTerminal( - @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, float x, float y, - @Nonnull Terminal terminal, boolean greyscale, - float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize, int light - ) - { - drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize, light ); - drawCursor( transform, buffer, x, y, terminal, greyscale ); - } - - // Called by WidgetTerminal - public static void drawTerminalImmediate( - @Nonnull PoseStack transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale, - float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize - ) - { - MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() ); - VertexConsumer buffer = renderer.getBuffer( RenderTypes.GUI_TERMINAL ); - drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize, FULL_BRIGHT_LIGHTMAP ); - renderer.endBatch(); - } - - public static void drawEmptyTerminal( @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, float x, float y, float width, float height, int light ) - { - Colour colour = Colour.BLACK; - drawQuad( transform, buffer, x, y, width, height, colour.getR(), colour.getG(), colour.getB(), light ); - } - - public static void drawEmptyTerminalImmediate( @Nonnull PoseStack transform, float x, float y, float width, float height ) - { - MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() ); - VertexConsumer buffer = renderer.getBuffer( RenderTypes.GUI_TERMINAL ); - drawEmptyTerminal( transform, buffer, x, y, width, height, FULL_BRIGHT_LIGHTMAP ); - renderer.endBatch(); - } - - private static void vertex( Matrix4f poseMatrix, Matrix3f normalMatrix, VertexConsumer buffer, float x, float y, float z, float r, float g, float b, float u, float v, int light ) - { - buffer.vertex( poseMatrix, x, y, z ).color( r, g, b, 1.0f ).uv( u, v ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normalMatrix, 0f, 0f, 1f ).endVertex(); - } - -} diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 5eb8cbc8f..14c24a9e1 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -10,7 +10,6 @@ import dan200.computercraft.client.gui.widgets.ComputerSidebar; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.render.ComputerBorderRenderer; -import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import net.minecraft.network.chat.Component; @@ -19,6 +18,7 @@ import javax.annotation.Nonnull; import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER; +import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; public final class GuiComputer extends ComputerScreenBase { @@ -78,7 +78,7 @@ public void renderBg( @Nonnull PoseStack stack, float partialTicks, int mouseX, // Draw a border around the terminal ComputerBorderRenderer.renderFromGui( ComputerBorderRenderer.getTexture( family ), terminal.x, terminal.y, getBlitOffset(), - RenderTypes.FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight() + FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight() ); ComputerSidebar.renderBackground( stack, leftPos, topPos + sidebarYOffset ); } diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index bae7fd8fd..4a5895ec8 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -6,22 +6,25 @@ package dan200.computercraft.client.gui.widgets; import com.mojang.blaze3d.vertex.PoseStack; -import dan200.computercraft.client.gui.FixedWidthFontRenderer; +import com.mojang.blaze3d.vertex.Tesselator; +import dan200.computercraft.client.render.RenderTypes; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.computer.core.ClientComputer; import net.minecraft.SharedConstants; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.TextComponent; import org.lwjgl.glfw.GLFW; import javax.annotation.Nonnull; import java.util.BitSet; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH; public class WidgetTerminal extends AbstractWidget { @@ -313,14 +316,24 @@ public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float { if( !visible ) return; Terminal terminal = computer.getTerminal(); + + var bufferSource = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() ); + var emitter = FixedWidthFontRenderer.toVertexConsumer( transform, bufferSource.getBuffer( RenderTypes.GUI_TERMINAL ) ); + if( terminal != null ) { - FixedWidthFontRenderer.drawTerminalImmediate( transform, innerX, innerY, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); + boolean greyscale = !computer.isColour(); + FixedWidthFontRenderer.drawTerminal( + emitter, + (float) innerX, (float) innerY, terminal, greyscale, (float) MARGIN, (float) MARGIN, (float) MARGIN, (float) MARGIN + ); } else { - FixedWidthFontRenderer.drawEmptyTerminalImmediate( transform, x, y, width, height ); + FixedWidthFontRenderer.drawEmptyTerminal( emitter, (float) x, (float) y, (float) width, (float) height ); } + + bufferSource.endBatch(); } @Override diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index c55dbcb8b..11c702413 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -12,7 +12,6 @@ import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.client.render.TurtleModelLoader; -import dan200.computercraft.client.render.TurtlePlayerRenderer; import dan200.computercraft.client.sound.SpeakerManager; import dan200.computercraft.fabric.events.CustomClientEvents; import dan200.computercraft.shared.Registry; @@ -36,14 +35,13 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; import net.fabricmc.fabric.api.client.rendering.v1.BlockEntityRendererRegistry; -import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; -import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; -import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry; +import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.item.ClampedItemPropertyFunction; +import net.minecraft.client.renderer.item.ItemProperties; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.inventory.InventoryMenu; @@ -106,8 +104,6 @@ public void onInitializeClient() TurtleModelLoader.INSTANCE.loadModel( name ) : null ); - EntityRendererRegistry.register( Registry.ModEntities.TURTLE_PLAYER, TurtlePlayerRenderer::new ); - registerItemProperty( "state", ( stack, world, player, integer ) -> ItemPocketComputer.getState( stack ) .ordinal(), @@ -125,18 +121,16 @@ public void onInitializeClient() // My IDE doesn't think so, but we do actually need these generics. private static void registerContainers() { - ScreenRegistry.>register( Registry.ModContainers.COMPUTER, GuiComputer::create ); - ScreenRegistry.>register( Registry.ModContainers.POCKET_COMPUTER, - GuiComputer::createPocket ); - ScreenRegistry.>register( Registry.ModContainers.POCKET_COMPUTER_NO_TERM, - NoTermComputerScreen::new ); - ScreenRegistry.register( Registry.ModContainers.TURTLE, GuiTurtle::new ); - - ScreenRegistry.register( Registry.ModContainers.PRINTER, GuiPrinter::new ); - ScreenRegistry.register( Registry.ModContainers.DISK_DRIVE, GuiDiskDrive::new ); - ScreenRegistry.register( Registry.ModContainers.PRINTOUT, GuiPrintout::new ); - - ScreenRegistry.>register( Registry.ModContainers.VIEW_COMPUTER, + MenuScreens.>register( Registry.ModContainers.COMPUTER, GuiComputer::create ); + MenuScreens.>register( Registry.ModContainers.POCKET_COMPUTER, GuiComputer::createPocket ); + MenuScreens.>register( Registry.ModContainers.POCKET_COMPUTER_NO_TERM, NoTermComputerScreen::new ); + MenuScreens.register( Registry.ModContainers.TURTLE, GuiTurtle::new ); + + MenuScreens.register( Registry.ModContainers.PRINTER, GuiPrinter::new ); + MenuScreens.register( Registry.ModContainers.DISK_DRIVE, GuiDiskDrive::new ); + MenuScreens.register( Registry.ModContainers.PRINTOUT, GuiPrintout::new ); + + MenuScreens.>register( Registry.ModContainers.VIEW_COMPUTER, GuiComputer::createView ); } @@ -162,7 +156,7 @@ public float unclampedCall( ItemStack itemStack, @Nullable ClientLevel clientLev }; for( Supplier item : items ) { - FabricModelPredicateProviderRegistry.register( item.get(), id, unclampedGetter ); + ItemProperties.register( item.get(), id, unclampedGetter ); } } } diff --git a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java index a17f50bc0..a807934cc 100644 --- a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java @@ -72,7 +72,6 @@ public ComputerBorderRenderer( PoseStack transform, VertexConsumer builder, int this.b = b; } - @Nonnull public static ResourceLocation getTexture( @Nonnull ComputerFamily family ) { diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 9ab59b94b..02847e27f 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -5,25 +5,24 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.vertex.*; -import com.mojang.math.Matrix3f; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Matrix4f; import com.mojang.math.Vector3f; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.client.gui.FixedWidthFontRenderer; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; import static dan200.computercraft.client.render.ComputerBorderRenderer.*; -import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH; /** * Emulates map rendering for pocket computers. @@ -37,7 +36,7 @@ private ItemPocketRenderer() } @Override - protected void renderItem( PoseStack transform, MultiBufferSource renderer, ItemStack stack, int light ) + protected void renderItem( PoseStack transform, MultiBufferSource bufferSource, ItemStack stack, int light ) { ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); Terminal terminal = computer == null ? null : computer.getTerminal(); @@ -75,32 +74,32 @@ protected void renderItem( PoseStack transform, MultiBufferSource renderer, Item ComputerFamily family = item.getFamily(); int frameColour = item.getColour( stack ); - renderFrame( transform, renderer, family, frameColour, light, width, height ); + renderFrame( transform, bufferSource, family, frameColour, light, width, height ); // Render the light int lightColour = ItemPocketComputer.getLightState( stack ); if( lightColour == -1 ) lightColour = Colour.BLACK.getHex(); - renderLight( transform, renderer, lightColour, width, height ); - VertexConsumer buffer = renderer.getBuffer( RenderTypes.ITEM_POCKET_TERMINAL ); + renderLight( transform, bufferSource, lightColour, width, height ); if( computer != null && terminal != null ) { FixedWidthFontRenderer.drawTerminal( - transform, buffer, - MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN, FULL_BRIGHT_LIGHTMAP + FixedWidthFontRenderer.toVertexConsumer( transform, bufferSource.getBuffer( RenderTypes.ITEM_POCKET_TERMINAL ) ), + MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); } else { FixedWidthFontRenderer.drawEmptyTerminal( - transform, buffer, - 0, 0, width, height, 0 ); + FixedWidthFontRenderer.toVertexConsumer( transform, bufferSource.getBuffer( RenderTypes.ITEM_POCKET_TERMINAL ) ), + 0, 0, width, height + ); } transform.popPose(); } - private static void renderFrame( PoseStack transform, MultiBufferSource renderer, ComputerFamily family, int colour, int light, int width, int height ) + private static void renderFrame( PoseStack transform, MultiBufferSource render, ComputerFamily family, int colour, int light, int width, int height ) { ResourceLocation texture = colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ); @@ -108,23 +107,22 @@ private static void renderFrame( PoseStack transform, MultiBufferSource renderer float g = ((colour >>> 8) & 0xFF) / 255.0f; float b = (colour & 0xFF) / 255.0f; - VertexConsumer buffer = renderer.getBuffer( RenderTypes.itemPocketBorder( texture ) ); + VertexConsumer buffer = render.getBuffer( RenderTypes.itemPocketBorder( texture ) ); ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, light, width, height, true, r, g, b ); } - private static void renderLight( PoseStack transform, MultiBufferSource renderer, int colour, int width, int height ) + private static void renderLight( PoseStack transform, MultiBufferSource render, int colour, int width, int height ) { - float r = ((colour >>> 16) & 0xFF) / 255.0f; - float g = ((colour >>> 8) & 0xFF) / 255.0f; - float b = (colour & 0xFF) / 255.0f; - float z = 0.001f; - - VertexConsumer buffer = renderer.getBuffer( RenderTypes.ITEM_POCKET_LIGHT ); - Matrix4f poseMatrix = transform.last().pose(); - Matrix3f normalMatrix = transform.last().normal(); - buffer.vertex( poseMatrix, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_START ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( FULL_BRIGHT_LIGHTMAP ).normal( normalMatrix, 0f, 0f, 1f ).endVertex(); - buffer.vertex( poseMatrix, width, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( FULL_BRIGHT_LIGHTMAP ).normal( normalMatrix, 0f, 0f, 1f ).endVertex(); - buffer.vertex( poseMatrix, width, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_END ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( FULL_BRIGHT_LIGHTMAP ).normal( normalMatrix, 0f, 0f, 1f ).endVertex(); - buffer.vertex( poseMatrix, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( FULL_BRIGHT_LIGHTMAP ).normal( normalMatrix, 0f, 0f, 1f ).endVertex(); + byte r = (byte) ((colour >>> 16) & 0xFF); + byte g = (byte) ((colour >>> 8) & 0xFF); + byte b = (byte) (colour & 0xFF); + byte[] c = new byte[] { r, g, b, (byte) 255 }; + + VertexConsumer buffer = render.getBuffer( RenderTypes.ITEM_POCKET_LIGHT ); + FixedWidthFontRenderer.drawQuad( + FixedWidthFontRenderer.toVertexConsumer( transform, buffer ), + width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT, + c, RenderTypes.FULL_BRIGHT_LIGHTMAP + ); } } diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index 422370065..da43dd393 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -12,9 +12,9 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.item.ItemStack; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.client.render.PrintoutRenderer.*; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH; diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java index 8552ad921..e54908690 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java @@ -7,105 +7,125 @@ import com.mojang.blaze3d.shaders.Uniform; import com.mojang.blaze3d.vertex.VertexFormat; -import dan200.computercraft.client.gui.FixedWidthFontRenderer; -import dan200.computercraft.shared.util.Palette; +import dan200.computercraft.client.FrameInfo; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.util.Colour; import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.server.packs.resources.ResourceProvider; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL31; import javax.annotation.Nullable; import java.io.IOException; -import java.nio.FloatBuffer; +import java.nio.ByteBuffer; + +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.getColour; public class MonitorTextureBufferShader extends ShaderInstance { + public static final int UNIFORM_SIZE = 4 * 4 * 16 + 4 + 4 + 2 * 4 + 4; + static final int TEXTURE_INDEX = GL13.GL_TEXTURE3; private static final Logger LOGGER = LogManager.getLogger(); - private final Uniform palette; - private final Uniform width; - private final Uniform height; + private final int monitorData; + private int uniformBuffer = 0; + + private final Uniform cursorBlink; public MonitorTextureBufferShader( ResourceProvider provider, String name, VertexFormat format ) throws IOException { super( provider, name, format ); + monitorData = GL31.glGetUniformBlockIndex( getId(), "MonitorData" ); + if( monitorData == -1 ) throw new IllegalStateException( "Could not find MonitorData uniform." ); - width = getUniformChecked( "Width" ); - height = getUniformChecked( "Height" ); - palette = new Uniform( "Palette", Uniform.UT_FLOAT3, 16 * 3, this ); - updateUniformLocation( palette ); + cursorBlink = getUniformChecked( "CursorBlink" ); Uniform tbo = getUniformChecked( "Tbo" ); if( tbo != null ) tbo.set( TEXTURE_INDEX - GL13.GL_TEXTURE0 ); } - void setupUniform( int width, int height, Palette palette, boolean greyscale ) - { - if( this.width != null ) this.width.set( width ); - if( this.height != null ) this.height.set( height ); - setupPalette( palette, greyscale ); - } - - private void setupPalette( Palette palette, boolean greyscale ) + public void setupUniform( int buffer ) { - if( this.palette == null ) return; + uniformBuffer = buffer; - FloatBuffer paletteBuffer = this.palette.getFloatBuffer(); - paletteBuffer.rewind(); - for( int i = 0; i < 16; i++ ) - { - double[] colour = palette.getColour( i ); - if( greyscale ) - { - float f = FixedWidthFontRenderer.toGreyscale( colour ); - paletteBuffer.put( f ).put( f ).put( f ); - } - else - { - paletteBuffer.put( (float) colour[0] ).put( (float) colour[1] ).put( (float) colour[2] ); - } - } + int cursorAlpha = FrameInfo.getGlobalCursorBlink() ? 1 : 0; + if( cursorBlink != null && cursorBlink.getIntBuffer().get( 0 ) != cursorAlpha ) cursorBlink.set( cursorAlpha ); } @Override public void apply() { super.apply(); - palette.upload(); + GL31.glBindBufferBase( GL31.GL_UNIFORM_BUFFER, monitorData, uniformBuffer ); } - @Override - public void close() + @Nullable + private Uniform getUniformChecked( String name ) { - palette.close(); - super.close(); + Uniform uniform = getUniform( name ); + if( uniform == null ) + { + LOGGER.warn( "Monitor shader {} should have uniform {}, but it was not present.", getName(), name ); + } + + return uniform; } - private void updateUniformLocation( Uniform uniform ) + public static void setTerminalData( ByteBuffer buffer, Terminal terminal ) { - int id = Uniform.glGetUniformLocation( getId(), uniform.getName() ); - if( id == -1 ) - { - LOGGER.warn( "Shader {} could not find uniform named {} in the specified shader program.", getName(), uniform.getName() ); - } - else + int width = terminal.getWidth(), height = terminal.getHeight(); + + int pos = 0; + for( int y = 0; y < height; y++ ) { - uniform.setLocation( id ); + TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y ); + for( int x = 0; x < width; x++ ) + { + buffer.put( pos, (byte) (text.charAt( x ) & 0xFF) ); + buffer.put( pos + 1, (byte) getColour( textColour.charAt( x ), Colour.WHITE ) ); + buffer.put( pos + 2, (byte) getColour( background.charAt( x ), Colour.BLACK ) ); + pos += 3; + } } + + buffer.limit( pos ); } - @Nullable - private Uniform getUniformChecked( String name ) + public static void setUniformData( ByteBuffer buffer, Terminal terminal, boolean greyscale ) { - Uniform uniform = getUniform( name ); - if( uniform == null ) + int pos = 0; + var palette = terminal.getPalette(); + for( int i = 0; i < 16; i++ ) { - LOGGER.warn( "Monitor shader {} should have uniform {}, but it was not present.", getName(), name ); + { + double[] colour = palette.getColour( i ); + if( greyscale ) + { + float f = FixedWidthFontRenderer.toGreyscale( colour ); + buffer.putFloat( pos, f ).putFloat( pos + 4, f ).putFloat( pos + 8, f ); + } + else + { + buffer.putFloat( pos, (float) colour[0] ).putFloat( pos + 4, (float) colour[1] ).putFloat( pos + 8, (float) colour[2] ); + } + } + + pos += 4 * 4; // std140 requires these are 4-wide } - return uniform; + boolean showCursor = FixedWidthFontRenderer.isCursorVisible( terminal ); + buffer + .putInt( pos, terminal.getWidth() ).putInt( pos + 4, terminal.getHeight() ) + .putInt( pos + 8, showCursor ? terminal.getCursorX() : -2 ) + .putInt( pos + 12, showCursor ? terminal.getCursorY() : -2 ) + .putInt( pos + 16, 15 - terminal.getTextColour() ); + + buffer.limit( UNIFORM_SIZE ); } } diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index af35f2253..7561b0a50 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -9,12 +9,12 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Matrix3f; import com.mojang.math.Matrix4f; -import dan200.computercraft.client.gui.FixedWidthFontRenderer; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.renderer.texture.OverlayTexture; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; public final class PrintoutRenderer @@ -58,25 +58,25 @@ private PrintoutRenderer() {} public static void drawText( PoseStack transform, VertexConsumer buffer, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours ) { + var emitter = FixedWidthFontRenderer.toVertexConsumer( transform, buffer ); for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) { - FixedWidthFontRenderer.drawString( transform, buffer, - x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT, - false, 0, 0, - light + FixedWidthFontRenderer.drawString( emitter, + x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], + Palette.DEFAULT, false, light ); } } public static void drawText( PoseStack transform, VertexConsumer buffer, int x, int y, int start, int light, String[] text, String[] colours ) { + var emitter = FixedWidthFontRenderer.toVertexConsumer( transform, buffer ); for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) { - FixedWidthFontRenderer.drawString( transform, buffer, + FixedWidthFontRenderer.drawString( emitter, x, y + line * FONT_HEIGHT, new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ), - null, Palette.DEFAULT, false, 0, 0, - light + Palette.DEFAULT, false, light ); } } diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 5cc3c97a5..c0dfc4986 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -8,21 +8,23 @@ import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.MemoryTracker; import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.*; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Matrix3f; import com.mojang.math.Matrix4f; import com.mojang.math.Vector3f; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.FrameInfo; -import dan200.computercraft.client.gui.FixedWidthFontRenderer; +import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; +import dan200.computercraft.client.util.DirectBuffers; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; -import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.core.BlockPos; @@ -34,8 +36,8 @@ import javax.annotation.Nonnull; import java.nio.ByteBuffer; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; -import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH; public class TileEntityMonitorRenderer implements BlockEntityRenderer { @@ -43,8 +45,8 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer -{ - public TurtlePlayerRenderer( EntityRendererProvider.Context renderManager ) - { - super( renderManager ); - } - - @Nonnull - @Override - public ResourceLocation getTextureLocation( @Nonnull TurtlePlayer entity ) - { - return ComputerBorderRenderer.BACKGROUND_NORMAL; - } - - @Override - public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource buffer, int packedLightIn ) - { - } -} diff --git a/src/main/java/dan200/computercraft/client/render/text/DirectFixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/render/text/DirectFixedWidthFontRenderer.java new file mode 100644 index 000000000..59c4e6737 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/text/DirectFixedWidthFontRenderer.java @@ -0,0 +1,238 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.render.text; + +import com.mojang.blaze3d.platform.MemoryTracker; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexConsumer; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.util.Colour; +import dan200.computercraft.shared.util.Palette; +import org.lwjgl.system.MemoryUtil; + +import javax.annotation.Nonnull; +import java.nio.ByteBuffer; + +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.*; +import static org.lwjgl.system.MemoryUtil.*; + +/** + * An optimised copy of {@link FixedWidthFontRenderer} emitter emits directly to a {@link ByteBuffer} rather than + * emitting to {@link VertexConsumer}. This allows us to emit vertices very quickly, when using the VBO renderer. + * + * There are some limitations here: + *
    + *
  • No transformation matrix (not needed for VBOs).
  • + *
  • Only works with {@link DefaultVertexFormat#POSITION_COLOR_TEX_LIGHTMAP}.
  • + *
  • The buffer MUST be allocated with {@link MemoryTracker}, and not through any other means.
  • + *
+ * + * Note this is almost an exact copy of {@link FixedWidthFontRenderer}. While the code duplication is unfortunate, + * it is measurably faster than introducing polymorphism into {@link FixedWidthFontRenderer}. + * + * IMPORTANT: When making changes to this class, please check if you need to make the same changes to + * {@link FixedWidthFontRenderer}. + */ +public final class DirectFixedWidthFontRenderer +{ + private DirectFixedWidthFontRenderer() + { + } + + private static void drawChar( ByteBuffer buffer, float x, float y, int index, byte[] colour ) + { + // Short circuit to avoid the common case - the texture should be blank here after all. + if( index == '\0' || index == ' ' ) return; + + int column = index % 16; + int row = index / 16; + + int xStart = 1 + column * (FONT_WIDTH + 2); + int yStart = 1 + row * (FONT_HEIGHT + 2); + + quad( + buffer, x, y, x + FONT_WIDTH, y + FONT_HEIGHT, Z_EPSILON, colour, + xStart / WIDTH, yStart / WIDTH, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH + ); + } + + private static void drawQuad( ByteBuffer emitter, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex ) + { + byte[] colour = palette.getByteColour( getColour( colourIndex, Colour.BLACK ), greyscale ); + quad( emitter, x, y, x + width, y + height, 0f, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END ); + } + + private static void drawBackground( + @Nonnull ByteBuffer buffer, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, + float leftMarginSize, float rightMarginSize, float height + ) + { + if( leftMarginSize > 0 ) + { + drawQuad( buffer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) ); + } + + if( rightMarginSize > 0 ) + { + drawQuad( buffer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) ); + } + + // Batch together runs of identical background cells. + int blockStart = 0; + char blockColour = '\0'; + for( int i = 0; i < backgroundColour.length(); i++ ) + { + char colourIndex = backgroundColour.charAt( i ); + if( colourIndex == blockColour ) continue; + + if( blockColour != '\0' ) + { + drawQuad( buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour ); + } + + blockColour = colourIndex; + blockStart = i; + } + + if( blockColour != '\0' ) + { + drawQuad( buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour ); + } + } + + private static void drawString( @Nonnull ByteBuffer buffer, float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull Palette palette, boolean greyscale ) + { + for( int i = 0; i < text.length(); i++ ) + { + byte[] colour = palette.getByteColour( getColour( textColour.charAt( i ), Colour.BLACK ), greyscale ); + + int index = text.charAt( i ); + if( index > 255 ) index = '?'; + drawChar( buffer, x + i * FONT_WIDTH, y, index, colour ); + } + } + + public static void drawTerminalWithoutCursor( + @Nonnull ByteBuffer buffer, float x, float y, @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) + { + Palette palette = terminal.getPalette(); + int height = terminal.getHeight(); + + // Top and bottom margins + drawBackground( + buffer, x, y - topMarginSize, terminal.getBackgroundColourLine( 0 ), palette, greyscale, + leftMarginSize, rightMarginSize, topMarginSize + ); + + drawBackground( + buffer, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine( height - 1 ), palette, greyscale, + leftMarginSize, rightMarginSize, bottomMarginSize + ); + + // The main text + for( int i = 0; i < height; i++ ) + { + float rowY = y + FONT_HEIGHT * i; + drawBackground( + buffer, x, rowY, terminal.getBackgroundColourLine( i ), palette, greyscale, + leftMarginSize, rightMarginSize, FONT_HEIGHT + ); + drawString( + buffer, x, rowY, terminal.getLine( i ), terminal.getTextColourLine( i ), + palette, greyscale + ); + } + } + + public static void drawCursor( @Nonnull ByteBuffer buffer, float x, float y, @Nonnull Terminal terminal, boolean greyscale ) + { + if( isCursorVisible( terminal ) ) + { + byte[] colour = terminal.getPalette().getByteColour( 15 - terminal.getTextColour(), greyscale ); + drawChar( buffer, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour ); + } + } + + public static int getVertexCount( Terminal terminal ) + { + return (1 + (terminal.getHeight() + 2) * terminal.getWidth() * 2) * 4; + } + + private static void quad( ByteBuffer buffer, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2 ) + { + // Emit a single quad to our buffer. This uses Unsafe (well, LWJGL's MemoryUtil) to directly blit bytes to the + // underlying buffer. This allows us to have a single bounds check up-front, rather than one for every write. + // This provides significant performance gains, at the cost of well, using Unsafe. + // Each vertex is 28 bytes, giving 112 bytes in total. Vertices are of the form (xyz:FFF)(rgba:BBBB)(uv1:FF)(uv2:SS), + // which matches the POSITION_COLOR_TEX_LIGHTMAP vertex format. + + int position = buffer.position(); + long addr = MemoryUtil.memAddress( buffer ); + + // We're doing terrible unsafe hacks below, so let's be really sure that what we're doing is reasonable. + if( position < 0 || 112 > buffer.limit() - position ) throw new IndexOutOfBoundsException(); + // Require the pointer to be aligned to a 32-bit boundary. + if( (addr & 3) != 0 ) throw new IllegalStateException( "Memory is not aligned" ); + // Also assert the length of the array. This appears to help elide bounds checks on the array in some circumstances. + if( rgba.length != 4 ) throw new IllegalStateException(); + + memPutFloat( addr + 0, x1 ); + memPutFloat( addr + 4, y1 ); + memPutFloat( addr + 8, z ); + memPutByte( addr + 12, rgba[0] ); + memPutByte( addr + 13, rgba[1] ); + memPutByte( addr + 14, rgba[2] ); + memPutByte( addr + 15, (byte) 255 ); + memPutFloat( addr + 16, u1 ); + memPutFloat( addr + 20, v1 ); + memPutShort( addr + 24, (short) 0xF0 ); + memPutShort( addr + 26, (short) 0xF0 ); + + memPutFloat( addr + 28, x1 ); + memPutFloat( addr + 32, y2 ); + memPutFloat( addr + 36, z ); + memPutByte( addr + 40, rgba[0] ); + memPutByte( addr + 41, rgba[1] ); + memPutByte( addr + 42, rgba[2] ); + memPutByte( addr + 43, (byte) 255 ); + memPutFloat( addr + 44, u1 ); + memPutFloat( addr + 48, v2 ); + memPutShort( addr + 52, (short) 0xF0 ); + memPutShort( addr + 54, (short) 0xF0 ); + + memPutFloat( addr + 56, x2 ); + memPutFloat( addr + 60, y2 ); + memPutFloat( addr + 64, z ); + memPutByte( addr + 68, rgba[0] ); + memPutByte( addr + 69, rgba[1] ); + memPutByte( addr + 70, rgba[2] ); + memPutByte( addr + 71, (byte) 255 ); + memPutFloat( addr + 72, u2 ); + memPutFloat( addr + 76, v2 ); + memPutShort( addr + 80, (short) 0xF0 ); + memPutShort( addr + 82, (short) 0xF0 ); + + memPutFloat( addr + 84, x2 ); + memPutFloat( addr + 88, y1 ); + memPutFloat( addr + 92, z ); + memPutByte( addr + 96, rgba[0] ); + memPutByte( addr + 97, rgba[1] ); + memPutByte( addr + 98, rgba[2] ); + memPutByte( addr + 99, (byte) 255 ); + memPutFloat( addr + 100, u2 ); + memPutFloat( addr + 104, v1 ); + memPutShort( addr + 108, (short) 0xF0 ); + memPutShort( addr + 110, (short) 0xF0 ); + + // Finally increment the position. + buffer.position( position + 112 ); + + // Well done for getting to the end of this method. I recommend you take a break and go look at cute puppies. + } +} diff --git a/src/main/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java new file mode 100644 index 000000000..574fb86b0 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java @@ -0,0 +1,243 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.render.text; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; +import dan200.computercraft.client.FrameInfo; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.util.Colour; +import dan200.computercraft.shared.util.Palette; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; + +import javax.annotation.Nonnull; + +import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; + +/** + * Handles rendering fixed width text and computer terminals. + * + * This class has several modes of usage: + *
    + *
  • {@link #drawString}: Drawing basic text without a terminal (such as for printouts). Unlike the other methods, + * this accepts a lightmap coordinate as, unlike terminals, printed pages render fullbright.
  • + *
  • {@link #drawTerminalWithoutCursor}/{@link #drawCursor}: Draw a terminal without a cursor and then draw the cursor + * separately. This is used by the monitor renderer to render the terminal to a VBO and draw the cursor dynamically. + *
  • + *
  • {@link #drawTerminal}: Draw a terminal with a cursor. This is used by the various computer GUIs to render the + * whole term.
  • + *
+ * + * IMPORTANT: When making changes to this class, please check if you need to make the same changes to + * {@link DirectFixedWidthFontRenderer}. + */ +public final class FixedWidthFontRenderer +{ + public static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" ); + + public static final int FONT_HEIGHT = 9; + public static final int FONT_WIDTH = 6; + static final float WIDTH = 256.0f; + + static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; + static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; + + private static final byte[] BLACK = new byte[] { byteColour( Colour.BLACK.getR() ), byteColour( Colour.BLACK.getR() ), byteColour( Colour.BLACK.getR() ), (byte) 255 }; + + public static final float Z_EPSILON = 0.001f; + + private FixedWidthFontRenderer() + { + } + + private static byte byteColour( float c ) + { + return (byte) (int) (c * 255); + } + + public static float toGreyscale( double[] rgb ) + { + return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); + } + + public static int getColour( char c, Colour def ) + { + return 15 - Terminal.getColour( c, def ); + } + + private static void drawChar( QuadEmitter emitter, float x, float y, int index, byte[] colour, int light ) + { + // Short circuit to avoid the common case - the texture should be blank here after all. + if( index == '\0' || index == ' ' ) return; + + int column = index % 16; + int row = index / 16; + + int xStart = 1 + column * (FONT_WIDTH + 2); + int yStart = 1 + row * (FONT_HEIGHT + 2); + + quad( + emitter, x, y, x + FONT_WIDTH, y + FONT_HEIGHT, Z_EPSILON, colour, + xStart / WIDTH, yStart / WIDTH, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH, light + ); + } + + public static void drawQuad( QuadEmitter emitter, float x, float y, float z, float width, float height, byte[] colour, int light ) + { + quad( emitter, x, y, x + width, y + height, z, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END, light ); + } + + private static void drawQuad( QuadEmitter emitter, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex, int light ) + { + byte[] colour = palette.getByteColour( getColour( colourIndex, Colour.BLACK ), greyscale ); + drawQuad( emitter, x, y, 0, width, height, colour, light ); + } + + private static void drawBackground( + @Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, + float leftMarginSize, float rightMarginSize, float height, int light + ) + { + if( leftMarginSize > 0 ) + { + drawQuad( emitter, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ), light ); + } + + if( rightMarginSize > 0 ) + { + drawQuad( emitter, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ), light ); + } + + // Batch together runs of identical background cells. + int blockStart = 0; + char blockColour = '\0'; + for( int i = 0; i < backgroundColour.length(); i++ ) + { + char colourIndex = backgroundColour.charAt( i ); + if( colourIndex == blockColour ) continue; + + if( blockColour != '\0' ) + { + drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour, light ); + } + + blockColour = colourIndex; + blockStart = i; + } + + if( blockColour != '\0' ) + { + drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour, light ); + } + } + + public static void drawString( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull Palette palette, boolean greyscale, int light ) + { + for( int i = 0; i < text.length(); i++ ) + { + byte[] colour = palette.getByteColour( getColour( textColour.charAt( i ), Colour.BLACK ), greyscale ); + + int index = text.charAt( i ); + if( index > 255 ) index = '?'; + drawChar( emitter, x + i * FONT_WIDTH, y, index, colour, light ); + } + + } + + public static void drawTerminalWithoutCursor( + @Nonnull QuadEmitter emitter, float x, float y, + @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) + { + Palette palette = terminal.getPalette(); + int height = terminal.getHeight(); + + // Top and bottom margins + drawBackground( + emitter, x, y - topMarginSize, terminal.getBackgroundColourLine( 0 ), palette, greyscale, + leftMarginSize, rightMarginSize, topMarginSize, FULL_BRIGHT_LIGHTMAP + ); + + drawBackground( + emitter, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine( height - 1 ), palette, greyscale, + leftMarginSize, rightMarginSize, bottomMarginSize, FULL_BRIGHT_LIGHTMAP + ); + + // The main text + for( int i = 0; i < height; i++ ) + { + float rowY = y + FixedWidthFontRenderer.FONT_HEIGHT * i; + drawBackground( + emitter, x, rowY, terminal.getBackgroundColourLine( i ), palette, greyscale, + leftMarginSize, rightMarginSize, FONT_HEIGHT, FULL_BRIGHT_LIGHTMAP + ); + drawString( + emitter, x, rowY, terminal.getLine( i ), terminal.getTextColourLine( i ), + palette, greyscale, FULL_BRIGHT_LIGHTMAP + ); + } + } + + public static boolean isCursorVisible( Terminal terminal ) + { + if( !terminal.getCursorBlink() ) return false; + + int cursorX = terminal.getCursorX(); + int cursorY = terminal.getCursorY(); + return cursorX >= 0 && cursorX < terminal.getWidth() && cursorY >= 0 && cursorY < terminal.getHeight(); + } + + public static void drawCursor( @Nonnull QuadEmitter emitter, float x, float y, @Nonnull Terminal terminal, boolean greyscale ) + { + if( isCursorVisible( terminal ) && FrameInfo.getGlobalCursorBlink() ) + { + byte[] colour = terminal.getPalette().getByteColour( 15 - terminal.getTextColour(), greyscale ); + drawChar( emitter, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, FULL_BRIGHT_LIGHTMAP ); + } + } + + public static void drawTerminal( + @Nonnull QuadEmitter emitter, float x, float y, + @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) + { + drawTerminalWithoutCursor( emitter, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); + drawCursor( emitter, x, y, terminal, greyscale ); + } + + public static void drawEmptyTerminal( @Nonnull QuadEmitter emitter, float x, float y, float width, float height ) + { + drawQuad( emitter, x, y, 0, width, height, BLACK, FULL_BRIGHT_LIGHTMAP ); + } + + public record QuadEmitter(Matrix4f poseMatrix, Vector3f normal, VertexConsumer consumer ) {} + + public static QuadEmitter toVertexConsumer( PoseStack transform, VertexConsumer consumer ) + { + var normal = new Vector3f( 0f, 0f, 1f ); + normal.transform( transform.last().normal() ); + return new QuadEmitter( transform.last().pose(), normal, consumer ); + } + + private static void quad( QuadEmitter c, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2, int light ) + { + var poseMatrix = c.poseMatrix(); + var consumer = c.consumer(); + var normal = c.normal(); + byte r = rgba[0], g = rgba[1], b = rgba[2], a = rgba[3]; + + consumer.vertex( poseMatrix, x1, y1, z ).color( rgba[0], rgba[1], rgba[2], rgba[3] ).uv( u1, v1 ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normal.x(), normal.y(), normal.z() ).endVertex(); + consumer.vertex( poseMatrix, x1, y2, z ).color( rgba[0], rgba[1], rgba[2], rgba[3] ).uv( u1, v2 ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normal.x(), normal.y(), normal.z() ).endVertex(); + consumer.vertex( poseMatrix, x2, y2, z ).color( rgba[0], rgba[1], rgba[2], rgba[3] ).uv( u2, v2 ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normal.x(), normal.y(), normal.z() ).endVertex(); + consumer.vertex( poseMatrix, x2, y1, z ).color( rgba[0], rgba[1], rgba[2], rgba[3] ).uv( u2, v1 ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normal.x(), normal.y(), normal.z() ).endVertex(); + } +} diff --git a/src/main/java/dan200/computercraft/client/sound/SpeakerInstance.java b/src/main/java/dan200/computercraft/client/sound/SpeakerInstance.java index 3ac5a6092..e52988174 100644 --- a/src/main/java/dan200/computercraft/client/sound/SpeakerInstance.java +++ b/src/main/java/dan200/computercraft/client/sound/SpeakerInstance.java @@ -6,10 +6,10 @@ package dan200.computercraft.client.sound; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.phys.Vec3; /** * An instance of a speaker, which is either playing a {@link DfpwmStream} stream or a normal sound. @@ -43,7 +43,7 @@ public synchronized void pushAudio( ByteBuf buffer ) } } - public void playAudio( Vec3 position, float volume ) + public void playAudio( SpeakerPosition position, float volume ) { var soundManager = Minecraft.getInstance().getSoundManager(); @@ -62,7 +62,7 @@ public void playAudio( Vec3 position, float volume ) } } - public void playSound( Vec3 position, ResourceLocation location, float volume, float pitch ) + public void playSound( SpeakerPosition position, ResourceLocation location, float volume, float pitch ) { var soundManager = Minecraft.getInstance().getSoundManager(); currentStream = null; @@ -77,7 +77,7 @@ public void playSound( Vec3 position, ResourceLocation location, float volume, f soundManager.play( sound ); } - void setPosition( Vec3 position ) + void setPosition( SpeakerPosition position ) { if( sound != null ) sound.setPosition( position ); } diff --git a/src/main/java/dan200/computercraft/client/sound/SpeakerManager.java b/src/main/java/dan200/computercraft/client/sound/SpeakerManager.java index f8c738461..4953cd763 100644 --- a/src/main/java/dan200/computercraft/client/sound/SpeakerManager.java +++ b/src/main/java/dan200/computercraft/client/sound/SpeakerManager.java @@ -5,10 +5,10 @@ */ package dan200.computercraft.client.sound; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import com.mojang.blaze3d.audio.Channel; import net.minecraft.client.resources.sounds.SoundInstance; import net.minecraft.client.sounds.SoundEngine; -import net.minecraft.world.phys.Vec3; import java.util.Map; import java.util.UUID; @@ -24,8 +24,7 @@ public class SpeakerManager // A return value of true cancels the event public static boolean playStreaming( SoundEngine engine, SoundInstance soundInstance, Channel channel ) { - if( !(soundInstance instanceof SpeakerSound sound) ) return false; - if( sound.stream == null ) return false; + if( !(soundInstance instanceof SpeakerSound sound) || sound.stream == null ) return false; channel.attachBufferStream( sound.stream ); channel.play(); @@ -46,7 +45,7 @@ public static void stopSound( UUID source ) if( sound != null ) sound.stop(); } - public static void moveSound( UUID source, Vec3 position ) + public static void moveSound( UUID source, SpeakerPosition position ) { SpeakerInstance sound = sounds.get( source ); if( sound != null ) sound.setPosition( position ); diff --git a/src/main/java/dan200/computercraft/client/sound/SpeakerSound.java b/src/main/java/dan200/computercraft/client/sound/SpeakerSound.java index 636ef307c..cacc83d07 100644 --- a/src/main/java/dan200/computercraft/client/sound/SpeakerSound.java +++ b/src/main/java/dan200/computercraft/client/sound/SpeakerSound.java @@ -6,14 +6,13 @@ package dan200.computercraft.client.sound; import com.mojang.blaze3d.audio.Channel; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import net.minecraft.client.resources.sounds.AbstractSoundInstance; import net.minecraft.client.resources.sounds.TickableSoundInstance; -import net.minecraft.client.sounds.AudioStream; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundSource; -import net.minecraft.world.phys.Vec3; +import net.minecraft.world.entity.Entity; -import javax.annotation.Nullable; import java.util.concurrent.Executor; public class SpeakerSound extends AbstractSoundInstance implements TickableSoundInstance @@ -22,7 +21,11 @@ public class SpeakerSound extends AbstractSoundInstance implements TickableSound Executor executor; DfpwmStream stream; - SpeakerSound( ResourceLocation sound, DfpwmStream stream, Vec3 position, float volume, float pitch ) + private Entity entity; + + private boolean stopped = false; + + SpeakerSound( ResourceLocation sound, DfpwmStream stream, SpeakerPosition position, float volume, float pitch ) { super( sound, SoundSource.RECORDS ); setPosition( position ); @@ -32,27 +35,34 @@ public class SpeakerSound extends AbstractSoundInstance implements TickableSound attenuation = Attenuation.LINEAR; } - void setPosition( Vec3 position ) + void setPosition( SpeakerPosition position ) { - x = (float) position.x(); - y = (float) position.y(); - z = (float) position.z(); + x = position.position().x; + y = position.position().y; + z = position.position().z; + entity = position.entity(); } @Override public boolean isStopped() { - return false; + return stopped; } @Override public void tick() { - } - - @Nullable - public AudioStream getStream() - { - return stream; + if( entity == null ) return; + if( !entity.isAlive() ) + { + stopped = true; + looping = false; + } + else + { + x = entity.getX(); + y = entity.getY(); + z = entity.getZ(); + } } } diff --git a/src/main/java/dan200/computercraft/client/util/DirectBuffers.java b/src/main/java/dan200/computercraft/client/util/DirectBuffers.java new file mode 100644 index 000000000..1c83fba3b --- /dev/null +++ b/src/main/java/dan200/computercraft/client/util/DirectBuffers.java @@ -0,0 +1,84 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.util; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferUploader; +import net.minecraft.Util; +import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GL15C; +import org.lwjgl.opengl.GL45C; + +import java.nio.ByteBuffer; + +/** + * Provides utilities to interact with OpenGL's buffer objects, either using direct state access or binding/unbinding + * it. + */ +public class DirectBuffers +{ + public static final boolean HAS_DSA; + static final boolean ON_LINUX = Util.getPlatform() == Util.OS.LINUX; + + static + { + var capabilities = GL.getCapabilities(); + HAS_DSA = capabilities.OpenGL45 || capabilities.GL_ARB_direct_state_access; + } + + public static int createBuffer() + { + return HAS_DSA ? GL45C.glCreateBuffers() : GL15C.glGenBuffers(); + } + + /** + * Delete a previously created buffer. + * + * On Linux, {@link GlStateManager#_glDeleteBuffers(int)} clears a buffer before deleting it. However, this involves + * binding and unbinding the buffer, conflicting with {@link BufferUploader}'s cache. This deletion method uses + * our existing {@link #setEmptyBufferData(int, int, int)}, which correctly handles clearing the buffer. + * + * @param type The buffer's type. + * @param id The buffer's ID. + */ + public static void deleteBuffer( int type, int id ) + { + RenderSystem.assertOnRenderThread(); + if( ON_LINUX ) DirectBuffers.setEmptyBufferData( type, id, GL15C.GL_DYNAMIC_DRAW ); + GL15C.glDeleteBuffers( id ); + } + + public static void setBufferData( int type, int id, ByteBuffer buffer, int flags ) + { + if( HAS_DSA ) + { + GL45C.glNamedBufferData( id, buffer, flags ); + } + else + { + if( type == GL15C.GL_ARRAY_BUFFER ) BufferUploader.reset(); + GlStateManager._glBindBuffer( type, id ); + GlStateManager._glBufferData( type, buffer, flags ); + GlStateManager._glBindBuffer( type, 0 ); + } + } + + public static void setEmptyBufferData( int type, int id, int flags ) + { + if( HAS_DSA ) + { + GL45C.glNamedBufferData( id, 0, flags ); + } + else + { + if( type == GL15C.GL_ARRAY_BUFFER ) BufferUploader.reset(); + GlStateManager._glBindBuffer( type, id ); + GlStateManager._glBufferData( type, 0, flags ); + GlStateManager._glBindBuffer( type, 0 ); + } + } +} diff --git a/src/main/java/dan200/computercraft/client/util/DirectVertexBuffer.java b/src/main/java/dan200/computercraft/client/util/DirectVertexBuffer.java new file mode 100644 index 000000000..47ad69263 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/util/DirectVertexBuffer.java @@ -0,0 +1,69 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.util; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.VertexBuffer; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.math.Matrix4f; +import net.minecraft.client.renderer.ShaderInstance; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL45C; + +import java.nio.ByteBuffer; + +/** + * A version of {@link VertexBuffer} which allows uploading {@link ByteBuffer}s directly. + * + * This should probably be its own class (rather than subclassing), but I need access to {@link VertexBuffer#drawWithShader}. + */ +public class DirectVertexBuffer extends VertexBuffer +{ + private int actualIndexCount; + + public DirectVertexBuffer() + { + if( DirectBuffers.HAS_DSA ) + { + RenderSystem.glDeleteBuffers( vertextBufferId ); + if( DirectBuffers.ON_LINUX ) BufferUploader.reset(); // See comment on DirectBuffers.deleteBuffer. + vertextBufferId = GL45C.glCreateBuffers(); + } + } + + public void upload( int vertexCount, VertexFormat.Mode mode, VertexFormat format, ByteBuffer buffer ) + { + RenderSystem.assertOnRenderThread(); + + DirectBuffers.setBufferData( GL15.GL_ARRAY_BUFFER, vertextBufferId, buffer, GL15.GL_STATIC_DRAW ); + + this.format = format; + this.mode = mode; + actualIndexCount = indexCount = mode.indexCount( vertexCount ); + indexType = VertexFormat.IndexType.SHORT; + sequentialIndices = true; + } + + public void drawWithShader( Matrix4f modelView, Matrix4f projection, ShaderInstance shader, int indexCount ) + { + this.indexCount = indexCount; + drawWithShader( modelView, projection, shader ); + this.indexCount = actualIndexCount; + } + + public int getIndexCount() + { + return actualIndexCount; + } + + @Override + public void close() + { + super.close(); + if( DirectBuffers.ON_LINUX ) BufferUploader.reset(); // See comment on DirectBuffers.deleteBuffer. + } +} diff --git a/src/main/java/dan200/computercraft/core/tracking/ComputerMBean.java b/src/main/java/dan200/computercraft/core/tracking/ComputerMBean.java index 965285beb..5d345f114 100644 --- a/src/main/java/dan200/computercraft/core/tracking/ComputerMBean.java +++ b/src/main/java/dan200/computercraft/core/tracking/ComputerMBean.java @@ -57,7 +57,8 @@ public static void register() { ManagementFactory.getPlatformMBeanServer().registerMBean( instance = new ComputerMBean(), new ObjectName( "dan200.computercraft:type=Computers" ) ); } - catch( InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException | MalformedObjectNameException e ) + catch( InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException | + MalformedObjectNameException e ) { ComputerCraft.log.warn( "Failed to register JMX bean", e ); } diff --git a/src/main/java/dan200/computercraft/data/BlockModelProvider.java b/src/main/java/dan200/computercraft/data/BlockModelProvider.java new file mode 100644 index 000000000..1ffc05762 --- /dev/null +++ b/src/main/java/dan200/computercraft/data/BlockModelProvider.java @@ -0,0 +1,250 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.data; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; +import dan200.computercraft.shared.computer.blocks.BlockComputer; +import dan200.computercraft.shared.computer.core.ComputerState; +import dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull; +import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem; +import dan200.computercraft.shared.peripheral.monitor.BlockMonitor; +import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState; +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider; +import net.minecraft.core.Direction; +import net.minecraft.data.models.BlockModelGenerators; +import net.minecraft.data.models.ItemModelGenerators; +import net.minecraft.data.models.blockstates.MultiVariantGenerator; +import net.minecraft.data.models.blockstates.PropertyDispatch; +import net.minecraft.data.models.blockstates.Variant; +import net.minecraft.data.models.blockstates.VariantProperties; +import net.minecraft.data.models.model.*; +import net.minecraft.resources.ResourceLocation; + +import java.util.Optional; + +import static net.minecraft.data.models.model.ModelLocationUtils.getModelLocation; +import static net.minecraft.data.models.model.TextureMapping.getBlockTexture; + +public class BlockModelProvider extends FabricModelProvider +{ + private static final ModelTemplate MONITOR_BASE = new ModelTemplate( + Optional.of( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) ), + Optional.empty(), + TextureSlot.FRONT, TextureSlot.SIDE, TextureSlot.TOP, TextureSlot.BACK + ); + private static final ModelTemplate MODEM = new ModelTemplate( + Optional.of( new ResourceLocation( ComputerCraft.MOD_ID, "block/modem" ) ), + Optional.empty(), + TextureSlot.FRONT, TextureSlot.BACK + ); + + public BlockModelProvider( FabricDataGenerator dataGenerator ) + { + super( dataGenerator ); + } + + @Override + public void generateBlockStateModels( BlockModelGenerators generators ) + { + registerComputer( generators, Registry.ModBlocks.COMPUTER_NORMAL ); + registerComputer( generators, Registry.ModBlocks.COMPUTER_ADVANCED ); + registerComputer( generators, Registry.ModBlocks.COMPUTER_COMMAND ); + + registerWirelessModem( generators, Registry.ModBlocks.WIRELESS_MODEM_NORMAL ); + registerWirelessModem( generators, Registry.ModBlocks.WIRELESS_MODEM_ADVANCED ); + + registerWiredModems( generators ); + + registerMonitors( generators, Registry.ModBlocks.MONITOR_NORMAL ); + registerMonitors( generators, Registry.ModBlocks.MONITOR_ADVANCED ); + + generators.createHorizontallyRotatedBlock( Registry.ModBlocks.SPEAKER, TexturedModel.ORIENTABLE_ONLY_TOP ); + generators.delegateItemModel( Registry.ModBlocks.SPEAKER, getModelLocation( Registry.ModBlocks.SPEAKER ) ); + } + + @Override + public void generateItemModels( ItemModelGenerators itemModelGenerator ) + { + + } + + private void registerComputer( BlockModelGenerators generators, BlockComputer block ) + { + var generator = PropertyDispatch.properties( BlockComputer.STATE, BlockComputer.FACING ); + for( ComputerState state : BlockComputer.STATE.getPossibleValues() ) + { + var model = ModelTemplates.CUBE_ORIENTABLE.create( + getModelLocation( block, "_" + state ), + new TextureMapping() + .put( TextureSlot.SIDE, getBlockTexture( block, "_side" ) ) + .put( TextureSlot.FRONT, getBlockTexture( block, "_front" + state.getTexture() ) ) + .put( TextureSlot.TOP, getBlockTexture( block, "_top" ) ), + generators.modelOutput + ); + + for( Direction facing : BlockComputer.FACING.getPossibleValues() ) + { + generator.select( state, facing, Variant.variant() + .with( VariantProperties.Y_ROT, toYAngle( facing ) ) + .with( VariantProperties.MODEL, model ) + ); + } + } + + generators.blockStateOutput.accept( MultiVariantGenerator.multiVariant( block ).with( generator ) ); + generators.delegateItemModel( block, getModelLocation( block, "_blinking" ) ); + } + + private void registerWirelessModem( BlockModelGenerators generators, BlockWirelessModem block ) + { + var generator = PropertyDispatch.properties( BlockWirelessModem.FACING, BlockWirelessModem.ON ); + + for( boolean on : BlockWirelessModem.ON.getPossibleValues() ) + { + var model = modemModel( generators, getModelLocation( block, on ? "_on" : "_off" ), getBlockTexture( block, "_face" + (on ? "_on" : "") ) ); + + for( Direction facing : BlockWirelessModem.FACING.getPossibleValues() ) + { + generator.select( facing, on, Variant.variant() + .with( VariantProperties.X_ROT, toXAngle( facing ) ) + .with( VariantProperties.Y_ROT, toYAngle( facing ) ) + .with( VariantProperties.MODEL, model ) + ); + } + } + + generators.blockStateOutput.accept( MultiVariantGenerator.multiVariant( block ).with( generator ) ); + generators.delegateItemModel( block, getModelLocation( block, "_off" ) ); + } + + private void registerWiredModems( BlockModelGenerators generators ) + { + BlockWiredModemFull fullBlock = Registry.ModBlocks.WIRED_MODEM_FULL; + var fullBlockGenerator = PropertyDispatch.properties( BlockWiredModemFull.MODEM_ON, BlockWiredModemFull.PERIPHERAL_ON ); + for( boolean on : BlockWiredModemFull.MODEM_ON.getPossibleValues() ) + { + for( boolean peripheral : BlockWiredModemFull.PERIPHERAL_ON.getPossibleValues() ) + { + String suffix = (on ? "_on" : "_off") + (peripheral ? "_peripheral" : ""); + ResourceLocation faceTexture = new ResourceLocation( + ComputerCraft.MOD_ID, + "block/wired_modem_face" + (peripheral ? "_peripheral" : "") + (on ? "_on" : "") + ); + var fullBlockModel = ModelTemplates.CUBE_ALL.create( + getModelLocation( fullBlock, suffix ), + new TextureMapping().put( TextureSlot.ALL, faceTexture ), + generators.modelOutput + ); + + fullBlockGenerator.select( on, peripheral, Variant.variant().with( VariantProperties.MODEL, fullBlockModel ) ); + + modemModel( generators, new ResourceLocation( ComputerCraft.MOD_ID, "block/wired_modem" + suffix ), faceTexture ); + } + } + + + generators.blockStateOutput.accept( MultiVariantGenerator.multiVariant( fullBlock ).with( fullBlockGenerator ) ); + generators.delegateItemModel( fullBlock, getModelLocation( fullBlock, "_off" ) ); + generators.delegateItemModel( Registry.ModItems.WIRED_MODEM, new ResourceLocation( ComputerCraft.MOD_ID, "block/wired_modem_off" ) ); + } + + private ResourceLocation modemModel( BlockModelGenerators generators, ResourceLocation name, ResourceLocation texture ) + { + return MODEM.create( + name, + new TextureMapping() + .put( TextureSlot.FRONT, texture ) + .put( TextureSlot.BACK, new ResourceLocation( ComputerCraft.MOD_ID, "block/modem_back" ) ), + generators.modelOutput + ); + } + + private void registerMonitors( BlockModelGenerators generators, BlockMonitor block ) + { + monitorModel( generators, block, "", 16, 4, 0, 32 ); + monitorModel( generators, block, "_d", 20, 7, 0, 36 ); + monitorModel( generators, block, "_l", 19, 4, 1, 33 ); + monitorModel( generators, block, "_ld", 31, 7, 1, 45 ); + monitorModel( generators, block, "_lr", 18, 4, 2, 34 ); + monitorModel( generators, block, "_lrd", 30, 7, 2, 46 ); + monitorModel( generators, block, "_lru", 24, 5, 2, 40 ); + monitorModel( generators, block, "_lrud", 27, 6, 2, 43 ); + monitorModel( generators, block, "_lu", 25, 5, 1, 39 ); + monitorModel( generators, block, "_lud", 28, 6, 1, 42 ); + monitorModel( generators, block, "_r", 17, 4, 3, 35 ); + monitorModel( generators, block, "_rd", 29, 7, 3, 47 ); + monitorModel( generators, block, "_ru", 23, 5, 3, 41 ); + monitorModel( generators, block, "_rud", 26, 6, 3, 44 ); + monitorModel( generators, block, "_u", 22, 5, 0, 38 ); + monitorModel( generators, block, "_ud", 21, 6, 0, 37 ); + + var generator = PropertyDispatch.properties( BlockMonitor.STATE, BlockMonitor.FACING, BlockMonitor.ORIENTATION ); + for( MonitorEdgeState edge : BlockMonitor.STATE.getPossibleValues() ) + { + String suffix = edge == MonitorEdgeState.NONE ? "" : "_" + edge.getSerializedName(); + var model = getModelLocation( block, suffix ); + + for( Direction facing : BlockMonitor.FACING.getPossibleValues() ) + { + for( Direction orientation : BlockMonitor.ORIENTATION.getPossibleValues() ) + { + generator.select( edge, facing, orientation, Variant.variant() + .with( VariantProperties.MODEL, model ) + .with( VariantProperties.X_ROT, toXAngle( orientation ) ) + .with( VariantProperties.Y_ROT, toYAngle( facing ) ) + ); + } + } + } + + generators.blockStateOutput.accept( MultiVariantGenerator.multiVariant( block ).with( generator ) ); + generators.delegateItemModel( block, monitorModel( generators, block, "_item", 15, 4, 0, 32 ) ); + } + + private ResourceLocation monitorModel( BlockModelGenerators generators, BlockMonitor block, String corners, int front, int side, int top, int back ) + { + return MONITOR_BASE.create( + getModelLocation( block, corners ), + new TextureMapping() + .put( TextureSlot.FRONT, getBlockTexture( block, "_" + front ) ) + .put( TextureSlot.SIDE, getBlockTexture( block, "_" + side ) ) + .put( TextureSlot.TOP, getBlockTexture( block, "_" + top ) ) + .put( TextureSlot.BACK, getBlockTexture( block, "_" + back ) ), + generators.modelOutput + ); + } + + private static VariantProperties.Rotation toXAngle( Direction direction ) + { + switch( direction ) + { + default: + return VariantProperties.Rotation.R0; + case UP: + return VariantProperties.Rotation.R270; + case DOWN: + return VariantProperties.Rotation.R90; + } + } + + private static VariantProperties.Rotation toYAngle( Direction direction ) + { + switch( direction ) + { + default: + case NORTH: + return VariantProperties.Rotation.R0; + case SOUTH: + return VariantProperties.Rotation.R180; + case EAST: + return VariantProperties.Rotation.R90; + case WEST: + return VariantProperties.Rotation.R270; + } + } +} diff --git a/src/main/java/dan200/computercraft/data/BlockTagsGenerator.java b/src/main/java/dan200/computercraft/data/BlockTagsGenerator.java new file mode 100644 index 000000000..5905987d2 --- /dev/null +++ b/src/main/java/dan200/computercraft/data/BlockTagsGenerator.java @@ -0,0 +1,84 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.data; + +import dan200.computercraft.shared.Registry; +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import org.jetbrains.annotations.NotNull; + +import static dan200.computercraft.api.ComputerCraftTags.Blocks.*; + +class BlockTagsGenerator extends FabricTagProvider.BlockTagProvider +{ + BlockTagsGenerator( FabricDataGenerator generator ) + { + super( generator ); + } + + @Override + protected void generateTags() + { + // Items + tag( COMPUTER ).add( + Registry.ModBlocks.COMPUTER_NORMAL, + Registry.ModBlocks.COMPUTER_ADVANCED, + Registry.ModBlocks.COMPUTER_COMMAND + ); + tag( TURTLE ).add( Registry.ModBlocks.TURTLE_NORMAL, Registry.ModBlocks.TURTLE_ADVANCED ); + tag( WIRED_MODEM ).add( Registry.ModBlocks.CABLE, Registry.ModBlocks.WIRED_MODEM_FULL ); + tag( MONITOR ).add( Registry.ModBlocks.MONITOR_NORMAL, Registry.ModBlocks.MONITOR_ADVANCED ); + + tag( TURTLE_ALWAYS_BREAKABLE ).forceAddTag( BlockTags.LEAVES ).add( + Blocks.BAMBOO, Blocks.BAMBOO_SAPLING // Bamboo isn't instabreak for some odd reason. + ); + + tag( TURTLE_SHOVEL_BREAKABLE ).forceAddTag( BlockTags.MINEABLE_WITH_SHOVEL ).add( + Blocks.MELON, + Blocks.PUMPKIN, + Blocks.CARVED_PUMPKIN, + Blocks.JACK_O_LANTERN + ); + + tag( TURTLE_HOE_BREAKABLE ).forceAddTag( BlockTags.CROPS ).forceAddTag( BlockTags.MINEABLE_WITH_HOE ).add( + Blocks.CACTUS, + Blocks.MELON, + Blocks.PUMPKIN, + Blocks.CARVED_PUMPKIN, + Blocks.JACK_O_LANTERN + ); + + tag( TURTLE_SWORD_BREAKABLE ).forceAddTag( BlockTags.WOOL ).add( Blocks.COBWEB ); + + // Make all blocks aside from command computer mineable. + tag( BlockTags.MINEABLE_WITH_PICKAXE ).add( + Registry.ModBlocks.COMPUTER_NORMAL, + Registry.ModBlocks.COMPUTER_ADVANCED, + Registry.ModBlocks.TURTLE_NORMAL, + Registry.ModBlocks.TURTLE_ADVANCED, + Registry.ModBlocks.SPEAKER, + Registry.ModBlocks.DISK_DRIVE, + Registry.ModBlocks.PRINTER, + Registry.ModBlocks.MONITOR_NORMAL, + Registry.ModBlocks.MONITOR_ADVANCED, + Registry.ModBlocks.WIRELESS_MODEM_NORMAL, + Registry.ModBlocks.WIRELESS_MODEM_ADVANCED, + Registry.ModBlocks.WIRED_MODEM_FULL, + Registry.ModBlocks.CABLE + ); + } + + @Override + protected FabricTagProvider.FabricTagBuilder tag( @NotNull TagKey tagKey ) + { + // Fun mapping weirdness here! + return super.getOrCreateTagBuilder( tagKey ); + } +} diff --git a/src/main/java/dan200/computercraft/data/ExtraConventionalItemTags.java b/src/main/java/dan200/computercraft/data/ExtraConventionalItemTags.java new file mode 100644 index 000000000..c7e204821 --- /dev/null +++ b/src/main/java/dan200/computercraft/data/ExtraConventionalItemTags.java @@ -0,0 +1,30 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.data; + +import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; +import net.fabricmc.fabric.impl.tag.convention.TagRegistration; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; + +/** + * Additional conventional item tags not built in to Fabric. + * + * @see ConventionalItemTags + */ +public class ExtraConventionalItemTags +{ + public static final TagKey ENDER_PEARLS = register( "ender_pearls" ); + public static final TagKey GOLD_BLOCKS = register( "gold_blocks" ); + public static final TagKey SKULLS = register( "skulls" ); + public static final TagKey STONES = register( "stones" ); + public static final TagKey WOODEN_CHESTS = register( "wooden_chests" ); + + private static TagKey register( String tagID ) + { + return TagRegistration.ITEM_TAG_REGISTRATION.registerCommon( tagID ); + } +} diff --git a/src/main/java/dan200/computercraft/data/Generators.java b/src/main/java/dan200/computercraft/data/Generators.java new file mode 100644 index 000000000..d933ffeb9 --- /dev/null +++ b/src/main/java/dan200/computercraft/data/Generators.java @@ -0,0 +1,24 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.data; + +import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; + +public class Generators implements DataGeneratorEntrypoint +{ + @Override + public void onInitializeDataGenerator( FabricDataGenerator generator ) + { + generator.addProvider( new RecipeGenerator( generator ) ); + generator.addProvider( new LootTableGenerator( generator ) ); + generator.addProvider( new BlockModelProvider( generator ) ); + + BlockTagsGenerator blockTags = new BlockTagsGenerator( generator ); + generator.addProvider( blockTags ); + generator.addProvider( new ItemTagsGenerator( generator, blockTags ) ); + } +} diff --git a/src/main/java/dan200/computercraft/data/ItemTagsGenerator.java b/src/main/java/dan200/computercraft/data/ItemTagsGenerator.java new file mode 100644 index 000000000..a1c63534c --- /dev/null +++ b/src/main/java/dan200/computercraft/data/ItemTagsGenerator.java @@ -0,0 +1,67 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.data; + +import dan200.computercraft.api.ComputerCraftTags.Blocks; +import dan200.computercraft.shared.Registry; +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.item.Items; + +import static dan200.computercraft.api.ComputerCraftTags.Items.*; + +class ItemTagsGenerator extends FabricTagProvider.ItemTagProvider +{ + ItemTagsGenerator( FabricDataGenerator generator, BlockTagsGenerator blockTags ) + { + super( generator, blockTags ); + } + + @Override + protected void generateTags() + { + copy( Blocks.COMPUTER, COMPUTER ); + copy( Blocks.TURTLE, TURTLE ); + tag( WIRED_MODEM ).add( Registry.ModItems.WIRED_MODEM, Registry.ModItems.WIRED_MODEM_FULL ); + copy( Blocks.MONITOR, MONITOR ); + + tag( ItemTags.PIGLIN_LOVED ).add( + Registry.ModItems.COMPUTER_ADVANCED, Registry.ModItems.TURTLE_ADVANCED, + Registry.ModItems.WIRELESS_MODEM_ADVANCED, Registry.ModItems.POCKET_COMPUTER_ADVANCED, + Registry.ModItems.MONITOR_ADVANCED + ); + + tag( ExtraConventionalItemTags.ENDER_PEARLS ).add( Items.ENDER_PEARL ); + tag( ExtraConventionalItemTags.GOLD_BLOCKS ).add( Items.GOLD_BLOCK ); + tag( ExtraConventionalItemTags.SKULLS ).add( + Items.CREEPER_HEAD, + Items.DRAGON_HEAD, + Items.PLAYER_HEAD, + Items.SKELETON_SKULL, + Items.WITHER_SKELETON_SKULL, + Items.ZOMBIE_HEAD + ); + tag( ExtraConventionalItemTags.STONES ).add( + Items.ANDESITE, + Items.DIORITE, + Items.GRANITE, + Items.INFESTED_STONE, + Items.STONE, + Items.POLISHED_ANDESITE, + Items.POLISHED_DIORITE, + Items.POLISHED_GRANITE, + Items.DEEPSLATE, + Items.POLISHED_DEEPSLATE, + Items.INFESTED_DEEPSLATE, + Items.TUFF + ); + tag( ExtraConventionalItemTags.WOODEN_CHESTS ).add( + Items.CHEST, + Items.TRAPPED_CHEST + ); + } +} diff --git a/src/main/java/dan200/computercraft/data/LootTableGenerator.java b/src/main/java/dan200/computercraft/data/LootTableGenerator.java new file mode 100644 index 000000000..1ac4c1dab --- /dev/null +++ b/src/main/java/dan200/computercraft/data/LootTableGenerator.java @@ -0,0 +1,112 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.data; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; +import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; +import dan200.computercraft.shared.data.HasComputerIdLootCondition; +import dan200.computercraft.shared.data.PlayerCreativeLootCondition; +import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; +import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant; +import net.minecraft.advancements.critereon.StatePropertiesPredicate; +import net.minecraft.data.DataGenerator; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.storage.loot.LootPool; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.entries.DynamicLoot; +import net.minecraft.world.level.storage.loot.entries.LootItem; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.minecraft.world.level.storage.loot.predicates.AlternativeLootItemCondition; +import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition; +import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition; +import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; + +import java.util.function.BiConsumer; + +class LootTableGenerator extends LootTableProvider +{ + LootTableGenerator( DataGenerator generator ) + { + super( generator ); + } + + @Override + protected void registerLoot( BiConsumer add ) + { + basicDrop( add, Registry.ModBlocks.DISK_DRIVE ); + basicDrop( add, Registry.ModBlocks.MONITOR_NORMAL ); + basicDrop( add, Registry.ModBlocks.MONITOR_ADVANCED ); + basicDrop( add, Registry.ModBlocks.PRINTER ); + basicDrop( add, Registry.ModBlocks.SPEAKER ); + basicDrop( add, Registry.ModBlocks.WIRED_MODEM_FULL ); + basicDrop( add, Registry.ModBlocks.WIRELESS_MODEM_NORMAL ); + basicDrop( add, Registry.ModBlocks.WIRELESS_MODEM_ADVANCED ); + + computerDrop( add, Registry.ModBlocks.COMPUTER_NORMAL ); + computerDrop( add, Registry.ModBlocks.COMPUTER_ADVANCED ); + computerDrop( add, Registry.ModBlocks.COMPUTER_COMMAND ); + computerDrop( add, Registry.ModBlocks.TURTLE_NORMAL ); + computerDrop( add, Registry.ModBlocks.TURTLE_ADVANCED ); + + add.accept( Registry.ModBlocks.CABLE.getLootTable(), LootTable + .lootTable() + .setParamSet( LootContextParamSets.BLOCK ) + .withPool( LootPool.lootPool() + .setRolls( ConstantValue.exactly( 1 ) ) + .add( LootItem.lootTableItem( Registry.ModItems.CABLE ) ) + .when( ExplosionCondition.survivesExplosion() ) + .when( LootItemBlockStatePropertyCondition.hasBlockStateProperties( Registry.ModBlocks.CABLE ) + .setProperties( StatePropertiesPredicate.Builder.properties().hasProperty( BlockCable.CABLE, true ) ) + ) + ) + .withPool( LootPool.lootPool() + .setRolls( ConstantValue.exactly( 1 ) ) + .add( LootItem.lootTableItem( Registry.ModItems.WIRED_MODEM ) ) + .when( ExplosionCondition.survivesExplosion() ) + .when( LootItemBlockStatePropertyCondition.hasBlockStateProperties( Registry.ModBlocks.CABLE ) + .setProperties( StatePropertiesPredicate.Builder.properties().hasProperty( BlockCable.MODEM, CableModemVariant.None ) ) + .invert() + ) + ) + .build() ); + + // TODO: LOOT_TREASURE_DISK + /*add.accept( CommonHooks.LOOT_TREASURE_DISK, LootTable + .lootTable() + .setParamSet( LootContextParamSets.ALL_PARAMS ) + .build() );*/ + } + + private static void basicDrop( BiConsumer add, Block block ) + { + add.accept( block.getLootTable(), LootTable + .lootTable() + .setParamSet( LootContextParamSets.BLOCK ) + .withPool( LootPool.lootPool() + .setRolls( ConstantValue.exactly( 1 ) ) + .add( LootItem.lootTableItem( block ) ) + .when( ExplosionCondition.survivesExplosion() ) + ).build() ); + } + + private static void computerDrop( BiConsumer add, Block block ) + { + add.accept( block.getLootTable(), LootTable + .lootTable() + .setParamSet( LootContextParamSets.BLOCK ) + .withPool( LootPool.lootPool() + .setRolls( ConstantValue.exactly( 1 ) ) + .add( DynamicLoot.dynamicEntry( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) ) + .when( AlternativeLootItemCondition.alternative( + BlockNamedEntityLootCondition.BUILDER, + HasComputerIdLootCondition.BUILDER, + PlayerCreativeLootCondition.BUILDER.invert() + ) ) + ).build() ); + } +} diff --git a/src/main/java/dan200/computercraft/data/LootTableProvider.java b/src/main/java/dan200/computercraft/data/LootTableProvider.java new file mode 100644 index 000000000..0d28f77b8 --- /dev/null +++ b/src/main/java/dan200/computercraft/data/LootTableProvider.java @@ -0,0 +1,91 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.data; + +import com.google.common.collect.Multimap; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import dan200.computercraft.ComputerCraft; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.DataProvider; +import net.minecraft.data.HashCache; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.LootTables; +import net.minecraft.world.level.storage.loot.ValidationContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; + +/** + * An alternative to {@link net.minecraft.data.loot.LootTableProvider}, with a more flexible interface. + */ +abstract class LootTableProvider implements DataProvider +{ + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + + private final DataGenerator generator; + + LootTableProvider( DataGenerator generator ) + { + this.generator = generator; + } + + @Override + public void run( @Nonnull HashCache cache ) + { + Map tables = new HashMap<>(); + ValidationContext validation = new ValidationContext( LootContextParamSets.ALL_PARAMS, x -> null, tables::get ); + + registerLoot( ( id, table ) -> { + if( tables.containsKey( id ) ) validation.reportProblem( "Duplicate loot tables for " + id ); + tables.put( id, table ); + } ); + + tables.forEach( ( key, value ) -> LootTables.validate( validation, key, value ) ); + + Multimap problems = validation.getProblems(); + if( !problems.isEmpty() ) + { + problems.forEach( ( child, problem ) -> + ComputerCraft.log.warn( "Found validation problem in " + child + ": " + problem ) ); + throw new IllegalStateException( "Failed to validate loot tables, see logs" ); + } + + tables.forEach( ( key, value ) -> { + Path path = getPath( key ); + try + { + DataProvider.save( GSON, cache, LootTables.serialize( value ), path ); + } + catch( IOException e ) + { + ComputerCraft.log.error( "Couldn't save loot table {}", path, e ); + } + } ); + } + + protected abstract void registerLoot( BiConsumer add ); + + @Nonnull + @Override + public String getName() + { + return "LootTables"; + } + + private Path getPath( ResourceLocation id ) + { + return generator.getOutputFolder() + .resolve( "data" ).resolve( id.getNamespace() ).resolve( "loot_tables" ) + .resolve( id.getPath() + ".json" ); + } +} diff --git a/src/main/java/dan200/computercraft/data/RecipeGenerator.java b/src/main/java/dan200/computercraft/data/RecipeGenerator.java new file mode 100644 index 000000000..adba89d4e --- /dev/null +++ b/src/main/java/dan200/computercraft/data/RecipeGenerator.java @@ -0,0 +1,395 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.data; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.PocketUpgrades; +import dan200.computercraft.shared.Registry; +import dan200.computercraft.shared.TurtleUpgrades; +import dan200.computercraft.shared.common.ColourableRecipe; +import dan200.computercraft.shared.common.IColouredItem; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.media.recipes.DiskRecipe; +import dan200.computercraft.shared.media.recipes.PrintoutRecipe; +import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; +import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe; +import dan200.computercraft.shared.turtle.items.TurtleItemFactory; +import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; +import dan200.computercraft.shared.util.Colour; +import dan200.computercraft.shared.util.ImpostorRecipe; +import dan200.computercraft.shared.util.ImpostorShapelessRecipe; +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; +import net.minecraft.advancements.critereon.InventoryChangeTrigger; +import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.data.recipes.FinishedRecipe; +import net.minecraft.data.recipes.ShapedRecipeBuilder; +import net.minecraft.data.recipes.ShapelessRecipeBuilder; +import net.minecraft.data.recipes.SpecialRecipeBuilder; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.*; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.SimpleRecipeSerializer; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.Blocks; + +import javax.annotation.Nonnull; +import java.util.Locale; +import java.util.function.Consumer; + +import static dan200.computercraft.api.ComputerCraftTags.Items.COMPUTER; +import static dan200.computercraft.api.ComputerCraftTags.Items.WIRED_MODEM; + +class RecipeGenerator extends FabricRecipeProvider +{ + RecipeGenerator( FabricDataGenerator generator ) + { + super( generator ); + } + + @Override + protected void generateRecipes( @Nonnull Consumer add ) + { + basicRecipes( add ); + diskColours( add ); + pocketUpgrades( add ); + turtleUpgrades( add ); + + addSpecial( add, PrintoutRecipe.SERIALIZER ); + addSpecial( add, DiskRecipe.SERIALIZER ); + addSpecial( add, ColourableRecipe.SERIALIZER ); + addSpecial( add, TurtleUpgradeRecipe.SERIALIZER ); + addSpecial( add, PocketComputerUpgradeRecipe.SERIALIZER ); + } + + /** + * Register a crafting recipe for a disk of every dye colour. + * + * @param add The callback to add recipes. + */ + private void diskColours( @Nonnull Consumer add ) + { + for( Colour colour : Colour.VALUES ) + { + ShapelessRecipeBuilder + .shapeless( Registry.ModItems.DISK ) + .requires( ConventionalItemTags.REDSTONE_DUSTS ) + .requires( Items.PAPER ) + .requires( DyeItem.byColor( ofColour( colour ) ) ) + .group( "computercraft:disk" ) + .unlockedBy( "has_drive", inventoryChange( Registry.ModBlocks.DISK_DRIVE ) ) + .save( RecipeWrapper.wrap( + ImpostorShapelessRecipe.SERIALIZER, add, + x -> x.putInt( IColouredItem.NBT_COLOUR, colour.getHex() ) + ), new ResourceLocation( ComputerCraft.MOD_ID, "disk_" + (colour.ordinal() + 1) ) ); + } + } + + /** + * Register a crafting recipe for each turtle upgrade. + * + * @param add The callback to add recipes. + */ + private void turtleUpgrades( @Nonnull Consumer add ) + { + for( ComputerFamily family : ComputerFamily.values() ) + { + ItemStack base = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ); + if( base.isEmpty() ) continue; + + String nameId = family.name().toLowerCase( Locale.ROOT ); + + TurtleUpgrades.getVanillaUpgrades().forEach( upgrade -> { + ItemStack result = TurtleItemFactory.create( -1, null, -1, family, null, upgrade, -1, null ); + ShapedRecipeBuilder + .shaped( result.getItem() ) + .group( String.format( "%s:turtle_%s", ComputerCraft.MOD_ID, nameId ) ) + .pattern( "#T" ) + .define( 'T', base.getItem() ) + .define( '#', upgrade.getCraftingItem().getItem() ) + .unlockedBy( "has_items", + inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) ) + .save( + RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ), + new ResourceLocation( ComputerCraft.MOD_ID, String.format( "turtle_%s/%s/%s", + nameId, upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath() + ) ) + ); + } ); + } + } + + /** + * Register a crafting recipe for each pocket upgrade. + * + * @param add The callback to add recipes. + */ + private void pocketUpgrades( @Nonnull Consumer add ) + { + for( ComputerFamily family : ComputerFamily.values() ) + { + ItemStack base = PocketComputerItemFactory.create( -1, null, -1, family, null ); + if( base.isEmpty() ) continue; + + String nameId = family.name().toLowerCase( Locale.ROOT ); + + PocketUpgrades.getVanillaUpgrades().forEach( upgrade -> { + ItemStack result = PocketComputerItemFactory.create( -1, null, -1, family, upgrade ); + ShapedRecipeBuilder + .shaped( result.getItem() ) + .group( String.format( "%s:pocket_%s", ComputerCraft.MOD_ID, nameId ) ) + .pattern( "#" ) + .pattern( "P" ) + .define( 'P', base.getItem() ) + .define( '#', upgrade.getCraftingItem().getItem() ) + .unlockedBy( "has_items", + inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) ) + .save( + RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ), + new ResourceLocation( ComputerCraft.MOD_ID, String.format( "pocket_%s/%s/%s", + nameId, upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath() + ) ) + ); + } ); + } + } + + private void basicRecipes( @Nonnull Consumer add ) + { + ShapedRecipeBuilder + .shaped( Registry.ModItems.CABLE, 6 ) + .pattern( " # " ) + .pattern( "#R#" ) + .pattern( " # " ) + .define( '#', ExtraConventionalItemTags.STONES ) + .define( 'R', ConventionalItemTags.REDSTONE_DUSTS ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .unlockedBy( "has_modem", inventoryChange( WIRED_MODEM ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.COMPUTER_NORMAL ) + .pattern( "###" ) + .pattern( "#R#" ) + .pattern( "#G#" ) + .define( '#', ExtraConventionalItemTags.STONES ) + .define( 'R', ConventionalItemTags.REDSTONE_DUSTS ) + .define( 'G', ConventionalItemTags.GLASS_PANES ) + .unlockedBy( "has_redstone", inventoryChange( ConventionalItemTags.REDSTONE_DUSTS ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.COMPUTER_ADVANCED ) + .pattern( "###" ) + .pattern( "#R#" ) + .pattern( "#G#" ) + .define( '#', ConventionalItemTags.GOLD_INGOTS ) + .define( 'R', ConventionalItemTags.REDSTONE_DUSTS ) + .define( 'G', ConventionalItemTags.GLASS_PANES ) + .unlockedBy( "has_components", inventoryChange( Items.REDSTONE, Items.GOLD_INGOT ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.COMPUTER_COMMAND ) + .pattern( "###" ) + .pattern( "#R#" ) + .pattern( "#G#" ) + .define( '#', ConventionalItemTags.GOLD_INGOTS ) + .define( 'R', Blocks.COMMAND_BLOCK ) + .define( 'G', ConventionalItemTags.GLASS_PANES ) + .unlockedBy( "has_components", inventoryChange( Blocks.COMMAND_BLOCK ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.DISK_DRIVE ) + .pattern( "###" ) + .pattern( "#R#" ) + .pattern( "#R#" ) + .define( '#', ExtraConventionalItemTags.STONES ) + .define( 'R', ConventionalItemTags.REDSTONE_DUSTS ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.MONITOR_NORMAL ) + .pattern( "###" ) + .pattern( "#G#" ) + .pattern( "###" ) + .define( '#', ExtraConventionalItemTags.STONES ) + .define( 'G', ConventionalItemTags.GLASS_PANES ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.MONITOR_ADVANCED, 4 ) + .pattern( "###" ) + .pattern( "#G#" ) + .pattern( "###" ) + .define( '#', ConventionalItemTags.GOLD_INGOTS ) + .define( 'G', ConventionalItemTags.GLASS_PANES ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModItems.POCKET_COMPUTER_NORMAL ) + .pattern( "###" ) + .pattern( "#A#" ) + .pattern( "#G#" ) + .define( '#', ExtraConventionalItemTags.STONES ) + .define( 'A', Items.GOLDEN_APPLE ) + .define( 'G', ConventionalItemTags.GLASS_PANES ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .unlockedBy( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModItems.POCKET_COMPUTER_ADVANCED ) + .pattern( "###" ) + .pattern( "#A#" ) + .pattern( "#G#" ) + .define( '#', ConventionalItemTags.GOLD_INGOTS ) + .define( 'A', Items.GOLDEN_APPLE ) + .define( 'G', ConventionalItemTags.GLASS_PANES ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .unlockedBy( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.PRINTER ) + .pattern( "###" ) + .pattern( "#R#" ) + .pattern( "#D#" ) + .define( '#', ExtraConventionalItemTags.STONES ) + .define( 'R', ConventionalItemTags.REDSTONE_DUSTS ) + .define( 'D', ConventionalItemTags.DYES ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.SPEAKER ) + .pattern( "###" ) + .pattern( "#N#" ) + .pattern( "#R#" ) + .define( '#', ExtraConventionalItemTags.STONES ) + .define( 'N', Blocks.NOTE_BLOCK ) + .define( 'R', ConventionalItemTags.REDSTONE_DUSTS ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModItems.WIRED_MODEM ) + .pattern( "###" ) + .pattern( "#R#" ) + .pattern( "###" ) + .define( '#', ExtraConventionalItemTags.STONES ) + .define( 'R', ConventionalItemTags.REDSTONE_DUSTS ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .unlockedBy( "has_cable", inventoryChange( Registry.ModItems.CABLE ) ) + .save( add ); + + ShapelessRecipeBuilder + .shapeless( Registry.ModBlocks.WIRED_MODEM_FULL ) + .requires( Registry.ModItems.WIRED_MODEM ) + .unlockedBy( "has_modem", inventoryChange( WIRED_MODEM ) ) + .save( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_from" ) ); + ShapelessRecipeBuilder + .shapeless( Registry.ModItems.WIRED_MODEM ) + .requires( Registry.ModBlocks.WIRED_MODEM_FULL ) + .unlockedBy( "has_modem", inventoryChange( WIRED_MODEM ) ) + .save( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_to" ) ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.WIRELESS_MODEM_NORMAL ) + .pattern( "###" ) + .pattern( "#E#" ) + .pattern( "###" ) + .define( '#', ExtraConventionalItemTags.STONES ) + .define( 'E', ExtraConventionalItemTags.ENDER_PEARLS ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .save( add ); + + ShapedRecipeBuilder + .shaped( Registry.ModBlocks.WIRELESS_MODEM_ADVANCED ) + .pattern( "###" ) + .pattern( "#E#" ) + .pattern( "###" ) + .define( '#', ConventionalItemTags.GOLD_INGOTS ) + .define( 'E', Items.ENDER_EYE ) + .unlockedBy( "has_computer", inventoryChange( COMPUTER ) ) + .unlockedBy( "has_wireless", inventoryChange( Registry.ModBlocks.WIRELESS_MODEM_NORMAL ) ) + .save( add ); + + ShapelessRecipeBuilder + .shapeless( Items.PLAYER_HEAD ) + .requires( ExtraConventionalItemTags.SKULLS ) + .requires( Registry.ModItems.MONITOR_NORMAL ) + .unlockedBy( "has_monitor", inventoryChange( Registry.ModItems.MONITOR_NORMAL ) ) + .save( + RecipeWrapper.wrap( RecipeSerializer.SHAPELESS_RECIPE, add, playerHead( "Cloudhunter", "6d074736-b1e9-4378-a99b-bd8777821c9c" ) ), + new ResourceLocation( ComputerCraft.MOD_ID, "skull_cloudy" ) + ); + + ShapelessRecipeBuilder + .shapeless( Items.PLAYER_HEAD ) + .requires( ExtraConventionalItemTags.SKULLS ) + .requires( Registry.ModItems.COMPUTER_NORMAL ) + .unlockedBy( "has_computer", inventoryChange( Registry.ModItems.COMPUTER_NORMAL ) ) + .save( + RecipeWrapper.wrap( RecipeSerializer.SHAPELESS_RECIPE, add, playerHead( "dan200", "f3c8d69b-0776-4512-8434-d1b2165909eb" ) ), + new ResourceLocation( ComputerCraft.MOD_ID, "skull_dan200" ) + ); + + ShapelessRecipeBuilder + .shapeless( Registry.ModItems.PRINTED_PAGES ) + .requires( Registry.ModItems.PRINTED_PAGE, 2 ) + .requires( Items.STRING ) + .unlockedBy( "has_printer", inventoryChange( Registry.ModBlocks.PRINTER ) ) + .save( RecipeWrapper.wrap( ImpostorShapelessRecipe.SERIALIZER, add ) ); + + ShapelessRecipeBuilder + .shapeless( Registry.ModItems.PRINTED_BOOK ) + .requires( Items.LEATHER ) + .requires( Registry.ModItems.PRINTED_PAGE, 1 ) + .requires( Items.STRING ) + .unlockedBy( "has_printer", inventoryChange( Registry.ModBlocks.PRINTER ) ) + .save( RecipeWrapper.wrap( ImpostorShapelessRecipe.SERIALIZER, add ) ); + } + + private static DyeColor ofColour( Colour colour ) + { + return DyeColor.byId( 15 - colour.ordinal() ); + } + + private static InventoryChangeTrigger.TriggerInstance inventoryChange( TagKey stack ) + { + return InventoryChangeTrigger.TriggerInstance.hasItems( ItemPredicate.Builder.item().of( stack ).build() ); + } + + private static InventoryChangeTrigger.TriggerInstance inventoryChange( ItemLike... stack ) + { + return InventoryChangeTrigger.TriggerInstance.hasItems( stack ); + } + + private static CompoundTag playerHead( String name, String uuid ) + { + CompoundTag owner = new CompoundTag(); + owner.putString( "Name", name ); + owner.putString( "Id", uuid ); + + CompoundTag tag = new CompoundTag(); + tag.put( "SkullOwner", owner ); + return tag; + } + + private static void addSpecial( Consumer add, SimpleRecipeSerializer special ) + { + var key = net.minecraft.core.Registry.RECIPE_SERIALIZER.getKey( special ); + SpecialRecipeBuilder.special( special ).save( add, key.toString() ); + } +} diff --git a/src/main/java/dan200/computercraft/data/RecipeWrapper.java b/src/main/java/dan200/computercraft/data/RecipeWrapper.java new file mode 100644 index 000000000..bc1b166d8 --- /dev/null +++ b/src/main/java/dan200/computercraft/data/RecipeWrapper.java @@ -0,0 +1,91 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.data; + +import com.google.gson.JsonObject; +import net.minecraft.data.recipes.FinishedRecipe; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.item.crafting.RecipeSerializer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.function.Consumer; + +/** + * Adapter for recipes which overrides the serializer and adds custom item NBT. + */ +final class RecipeWrapper implements FinishedRecipe +{ + private final FinishedRecipe recipe; + private final CompoundTag resultData; + private final RecipeSerializer serializer; + + private RecipeWrapper( FinishedRecipe recipe, CompoundTag resultData, RecipeSerializer serializer ) + { + this.resultData = resultData; + this.recipe = recipe; + this.serializer = serializer; + } + + public static Consumer wrap( RecipeSerializer serializer, Consumer original ) + { + return x -> original.accept( new RecipeWrapper( x, null, serializer ) ); + } + + public static Consumer wrap( RecipeSerializer serializer, Consumer original, CompoundTag resultData ) + { + return x -> original.accept( new RecipeWrapper( x, resultData, serializer ) ); + } + + public static Consumer wrap( RecipeSerializer serializer, Consumer original, Consumer resultData ) + { + CompoundTag tag = new CompoundTag(); + resultData.accept( tag ); + return x -> original.accept( new RecipeWrapper( x, tag, serializer ) ); + } + + @Override + public void serializeRecipeData( @Nonnull JsonObject jsonObject ) + { + recipe.serializeRecipeData( jsonObject ); + + if( resultData != null ) + { + JsonObject object = GsonHelper.getAsJsonObject( jsonObject, "result" ); + object.addProperty( "nbt", resultData.toString() ); + } + } + + @Nonnull + @Override + public ResourceLocation getId() + { + return recipe.getId(); + } + + @Nonnull + @Override + public RecipeSerializer getType() + { + return serializer; + } + + @Nullable + @Override + public JsonObject serializeAdvancement() + { + return recipe.serializeAdvancement(); + } + + @Nullable + @Override + public ResourceLocation getAdvancementId() + { + return recipe.getAdvancementId(); + } +} diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinChunkMap.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinChunkMap.java index dfa3fde3f..a69f0550b 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinChunkMap.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinChunkMap.java @@ -27,11 +27,11 @@ public class MixinChunkMap ServerLevel level; /* - * This mixin mimics the logic of Forge's ChunkWatchEvent.Watch but I don't believe it behaves as expected. Instead - * of firing once when the player initially come in server view distance of a chunk, it fires every time - * the chunk is checked against the player's view distance. This continually happens every tick that the player - * moves (or even rotates in place). - */ + * This mixin mimics the logic of Forge's ChunkWatchEvent.Watch but I don't believe it behaves as expected. Instead + * of firing once when the player initially come in server view distance of a chunk, it fires every time + * the chunk is checked against the player's view distance. This continually happens every tick that the player + * moves (or even rotates in place). + */ // @Inject( method = "updateChunkTracking", at = @At( value = "HEAD" ) ) // public void updateChunkTracking( ServerPlayer serverPlayer, ChunkPos chunkPos, MutableObject mutableObject, boolean bl, boolean bl2, CallbackInfo ci ) diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java index 9296a91c7..274b7d845 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java @@ -5,16 +5,16 @@ */ package dan200.computercraft.fabric.mixin; +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonParseException; import dan200.computercraft.fabric.util.ServerTranslationEntry; -import net.minecraft.util.StringDecomposer; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.network.chat.FormattedText; -import net.minecraft.network.chat.Style; -import net.minecraft.locale.Language; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; -import com.google.common.collect.ImmutableMap; -import com.google.gson.JsonParseException; +import net.minecraft.locale.Language; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.network.chat.Style; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.StringDecomposer; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; @@ -28,14 +28,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.BiConsumer; import java.util.stream.Collectors; @@ -60,14 +53,14 @@ private static void loadFromJson( InputStream inputStream, BiConsumer biConsumer ) { - Path path = modContainer.getPath( "assets/" + modContainer.getMetadata().getId() + "/lang/" + DEFAULT + ".json" ); - if ( !Files.exists( path ) ) return; + Optional path = modContainer.findPath( "assets/" + modContainer.getMetadata().getId() + "/lang/" + DEFAULT + ".json" ); + if( path.isEmpty() ) return; - try ( InputStream inputStream = Files.newInputStream( path ) ) + try( InputStream inputStream = Files.newInputStream( path.get() ) ) { loadFromJson( inputStream, biConsumer ); } - catch ( JsonParseException | IOException e ) + catch( JsonParseException | IOException e ) { LOGGER.error( "Couldn't read strings from " + path, e ); } @@ -78,19 +71,19 @@ private static void loadDefault( CallbackInfoReturnable cir ) { Map> translations = new HashMap<>(); - for ( ModContainer mod : FabricLoader.getInstance().getAllMods() ) + for( ModContainer mod : FabricLoader.getInstance().getAllMods() ) { loadModLangFile( mod, ( k, v ) -> { - if ( !translations.containsKey( k ) ) translations.put( k, new ArrayList<>() ); + if( !translations.containsKey( k ) ) translations.put( k, new ArrayList<>() ); translations.get( k ).add( new ServerTranslationEntry( mod.getMetadata(), k, v ) ); } ); } ImmutableMap.Builder builder = ImmutableMap.builder(); - for ( Map.Entry> keyEntry : translations.entrySet() ) + for( Map.Entry> keyEntry : translations.entrySet() ) { - if ( keyEntry.getValue().size() == 1 ) + if( keyEntry.getValue().size() == 1 ) { // Only one value provided for this key builder.put( keyEntry.getKey(), keyEntry.getValue().get( 0 ).value() ); diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinSoundEngine.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinSoundEngine.java index 6add67f91..1c627afc4 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinSoundEngine.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinSoundEngine.java @@ -21,11 +21,13 @@ public class MixinSoundEngine { // Used to capture the SoundInstance argument passed to SoundEngine#play and the SoundEngine instance. // Not a thread-safe way to do it but this code is only called from the render thread as far as I can tell. - @Unique private static SoundInstance soundInstanceCapture; - @Unique private static SoundEngine thisCapture; + @Unique + private static SoundInstance soundInstanceCapture; + @Unique + private static SoundEngine thisCapture; @Inject( - method = "lambda$play$8(Lnet/minecraft/client/sounds/AudioStream;Lcom/mojang/blaze3d/audio/Channel;)V", + method = "method_19755(Lnet/minecraft/client/sounds/AudioStream;Lcom/mojang/blaze3d/audio/Channel;)V", at = @At( "HEAD" ), cancellable = true ) diff --git a/src/main/java/dan200/computercraft/fabric/util/ServerTranslationEntry.java b/src/main/java/dan200/computercraft/fabric/util/ServerTranslationEntry.java index 0b55baae3..3d6dc759c 100644 --- a/src/main/java/dan200/computercraft/fabric/util/ServerTranslationEntry.java +++ b/src/main/java/dan200/computercraft/fabric/util/ServerTranslationEntry.java @@ -12,7 +12,7 @@ import java.util.stream.Collectors; // A utility class for holding translation mappings prior collision resolution. -public record ServerTranslationEntry(ModMetadata providingModMetadata, String key, String value ) +public record ServerTranslationEntry(ModMetadata providingModMetadata, String key, String value) { public String getModId() { @@ -21,9 +21,9 @@ public String getModId() public Set getDependencyIds() { - Set deps = providingModMetadata.getDependencies().stream().map( ModDependency::getModId ) .collect( Collectors.toSet() ); + Set deps = providingModMetadata.getDependencies().stream().map( ModDependency::getModId ).collect( Collectors.toSet() ); // For the purposes of handling key collisions, all mods should depend on minecraft - if ( !getModId().equals( "minecraft" ) ) deps.add( "minecraft" ); + if( !getModId().equals( "minecraft" ) ) deps.add( "minecraft" ); return deps; } diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index 509902dbc..5aeaa9e3c 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -42,20 +42,17 @@ import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; import dan200.computercraft.shared.turtle.blocks.BlockTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle; -import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.upgrades.TurtleCraftingTable; import dan200.computercraft.shared.turtle.upgrades.TurtleModem; import dan200.computercraft.shared.turtle.upgrades.TurtleSpeaker; import dan200.computercraft.shared.turtle.upgrades.TurtleTool; +import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; -import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; import net.minecraft.core.BlockPos; import net.minecraft.core.cauldron.CauldronInteraction; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.MobCategory; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.*; @@ -83,7 +80,6 @@ public static void init() ModBlockEntities.CABLE, ModBlocks.CABLE, ModItems.CABLE, - ModEntities.TURTLE_PLAYER, ModContainers.COMPUTER, }; @@ -114,7 +110,7 @@ public static T register( String id, T value ) register( "computer_advanced", new BlockComputer<>( properties(), ComputerFamily.ADVANCED, () -> ModBlockEntities.COMPUTER_ADVANCED ) ); public static final BlockComputer COMPUTER_COMMAND = - register( "computer_command", new BlockComputer<>( properties().strength( -1, 6000000.0F ).requiresCorrectToolForDrops().noDrops(), ComputerFamily.COMMAND, () -> ModBlockEntities.COMPUTER_COMMAND ) ); + register( "computer_command", new BlockComputer<>( properties().strength( -1, 6000000.0F ), ComputerFamily.COMMAND, () -> ModBlockEntities.COMPUTER_COMMAND ) ); public static final BlockTurtle TURTLE_NORMAL = register( "turtle_normal", new BlockTurtle( turtleProperties(), ComputerFamily.NORMAL, () -> ModBlockEntities.TURTLE_NORMAL ) ); @@ -212,7 +208,10 @@ private static BlockEntityType ofBlock( Block block, public static final class ModItems { - private static final CreativeModeTab mainItemGroup = ComputerCraft.MAIN_GROUP; + private static final CreativeModeTab mainItemGroup = FabricItemGroupBuilder.build( + new ResourceLocation( MOD_ID, "main" ), + () -> new ItemStack( ModBlocks.COMPUTER_NORMAL ) + ).setRecipeFolderName( MOD_ID ); public static final ItemComputer COMPUTER_NORMAL = ofBlock( ModBlocks.COMPUTER_NORMAL, ItemComputer::new ); @@ -297,13 +296,6 @@ private static T register( String id, T item ) } } - public static class ModEntities - { - public static final EntityType TURTLE_PLAYER = - net.minecraft.core.Registry.register( net.minecraft.core.Registry.ENTITY_TYPE, new ResourceLocation( MOD_ID, "turtle_player" ), - EntityType.Builder.createNothing( MobCategory.MISC ).noSave().noSummon().sized( 0, 0 ).build( ComputerCraft.MOD_ID + ":turtle_player" ) ); - } - public static class ModContainers { public static final MenuType COMPUTER = @@ -330,9 +322,9 @@ public static class ModContainers public static final MenuType VIEW_COMPUTER = ContainerData.toType( new ResourceLocation( MOD_ID, "view_computer" ), ViewComputerContainerData::new, ContainerViewComputer::new ); - private static MenuType registerSimple( String id, ScreenHandlerRegistry.SimpleClientHandlerFactory function ) + private static MenuType registerSimple( String id, MenuType.MenuSupplier function ) { - return ScreenHandlerRegistry.registerSimple( new ResourceLocation( MOD_ID, id ), function ); + return net.minecraft.core.Registry.register( net.minecraft.core.Registry.MENU, new ResourceLocation( MOD_ID, id ), new MenuType( function ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index f271fbd88..792738da9 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -104,6 +104,7 @@ public static Stream getVanillaUpgrades() // Vanilla Minecraft upgrades Registry.TurtleUpgrades.diamondPickaxe, + Registry.TurtleUpgrades.netheritePickaxe, Registry.TurtleUpgrades.diamondAxe, Registry.TurtleUpgrades.diamondSword, Registry.TurtleUpgrades.diamondShovel, diff --git a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java index f7f5a90a6..7d4415a83 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java @@ -32,7 +32,7 @@ public static boolean isPlayer( CommandSourceStack output ) } @SuppressWarnings( "unchecked" ) - public static CompletableFuture suggestOnServer( CommandContext context, SuggestionsBuilder builder, Function, CompletableFuture> supplier ) + public static CompletableFuture suggestOnServer( CommandContext context, Function, CompletableFuture> supplier ) { Object source = context.getSource(); if( !(source instanceof SharedSuggestionProvider) ) diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java index 50f895847..c756c77e3 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java @@ -121,7 +121,7 @@ public CompletableFuture listSuggestions( CommandContext con } // Verify we've a command source and we're running on the server - return suggestOnServer( context, builder, s -> { + return suggestOnServer( context, s -> { if( remaining.startsWith( "@" ) ) { suggestComputers( builder, remaining, x -> { diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index d193f2e6b..09825a162 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -99,7 +99,7 @@ public CommandSourceStack getSource() } return new CommandSourceStack( receiver, - new Vec3( worldPosition.getX() + 0.5, worldPosition.getY() + 0.5, worldPosition.getZ() + 0.5 ), Vec2.ZERO, + Vec3.atCenterOf( worldPosition ), Vec2.ZERO, (ServerLevel) getLevel(), 2, name, new TextComponent( name ), getLevel().getServer(), null diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index 8c227fbde..1f6526644 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -9,6 +9,7 @@ import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; +import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.DyeColor; @@ -25,7 +26,7 @@ public class DiskRecipe extends CustomRecipe { private final Ingredient paper = Ingredient.of( Items.PAPER ); - private final Ingredient redstone = Ingredient.of( Items.REDSTONE ); + private final Ingredient redstone = Ingredient.of( ConventionalItemTags.REDSTONE_DUSTS ); public DiskRecipe( ResourceLocation id ) { diff --git a/src/main/java/dan200/computercraft/shared/network/client/SpeakerAudioClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/SpeakerAudioClientMessage.java index 04c9163d7..569477d2a 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/SpeakerAudioClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/SpeakerAudioClientMessage.java @@ -7,11 +7,11 @@ import dan200.computercraft.client.sound.SpeakerManager; import dan200.computercraft.shared.network.NetworkMessage; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import dan200.computercraft.shared.network.PacketContext; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; import java.nio.ByteBuffer; @@ -27,14 +27,14 @@ public class SpeakerAudioClientMessage implements NetworkMessage { private final UUID source; - private final Vec3 pos; + private final SpeakerPosition.Message pos; private final ByteBuffer content; private final float volume; - public SpeakerAudioClientMessage( UUID source, Vec3 pos, float volume, ByteBuffer content ) + public SpeakerAudioClientMessage( UUID source, SpeakerPosition pos, float volume, ByteBuffer content ) { this.source = source; - this.pos = pos; + this.pos = pos.asMessage(); this.content = content; this.volume = volume; } @@ -42,7 +42,7 @@ public SpeakerAudioClientMessage( UUID source, Vec3 pos, float volume, ByteBuffe public SpeakerAudioClientMessage( FriendlyByteBuf buf ) { source = buf.readUUID(); - pos = new Vec3( buf.readDouble(), buf.readDouble(), buf.readDouble() ); + pos = SpeakerPosition.Message.read( buf ); volume = buf.readFloat(); SpeakerManager.getSound( source ).pushAudio( buf ); @@ -53,9 +53,7 @@ public SpeakerAudioClientMessage( FriendlyByteBuf buf ) public void toBytes( @Nonnull FriendlyByteBuf buf ) { buf.writeUUID( source ); - buf.writeDouble( pos.x() ); - buf.writeDouble( pos.y() ); - buf.writeDouble( pos.z() ); + pos.write( buf ); buf.writeFloat( volume ); buf.writeBytes( content.duplicate() ); } @@ -64,6 +62,6 @@ public void toBytes( @Nonnull FriendlyByteBuf buf ) @Environment( EnvType.CLIENT ) public void handle( PacketContext context ) { - SpeakerManager.getSound( source ).playAudio( pos, volume ); + SpeakerManager.getSound( source ).playAudio( pos.reify(), volume ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java index 95f705fe4..bd98ab097 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java @@ -7,11 +7,11 @@ import dan200.computercraft.client.sound.SpeakerManager; import dan200.computercraft.shared.network.NetworkMessage; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import dan200.computercraft.shared.network.PacketContext; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; import java.util.UUID; @@ -26,33 +26,31 @@ public class SpeakerMoveClientMessage implements NetworkMessage { private final UUID source; - private final Vec3 pos; + private final SpeakerPosition.Message pos; - public SpeakerMoveClientMessage( UUID source, Vec3 pos ) + public SpeakerMoveClientMessage( UUID source, SpeakerPosition pos ) { this.source = source; - this.pos = pos; + this.pos = pos.asMessage(); } public SpeakerMoveClientMessage( FriendlyByteBuf buf ) { source = buf.readUUID(); - pos = new Vec3( buf.readDouble(), buf.readDouble(), buf.readDouble() ); + pos = SpeakerPosition.Message.read( buf ); } @Override public void toBytes( @Nonnull FriendlyByteBuf buf ) { buf.writeUUID( source ); - buf.writeDouble( pos.x() ); - buf.writeDouble( pos.y() ); - buf.writeDouble( pos.z() ); + pos.write( buf ); } @Override @Environment( EnvType.CLIENT ) public void handle( PacketContext context ) { - SpeakerManager.moveSound( source, pos ); + SpeakerManager.moveSound( source, pos.reify() ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java index e759d4ec1..71ea44485 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java @@ -10,9 +10,9 @@ import dan200.computercraft.shared.network.PacketContext; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; import java.util.UUID; @@ -27,15 +27,15 @@ public class SpeakerPlayClientMessage implements NetworkMessage { private final UUID source; - private final Vec3 pos; + private final SpeakerPosition.Message pos; private final ResourceLocation sound; private final float volume; private final float pitch; - public SpeakerPlayClientMessage( UUID source, Vec3 pos, ResourceLocation event, float volume, float pitch ) + public SpeakerPlayClientMessage( UUID source, SpeakerPosition pos, ResourceLocation event, float volume, float pitch ) { this.source = source; - this.pos = pos; + this.pos = pos.asMessage(); sound = event; this.volume = volume; this.pitch = pitch; @@ -44,7 +44,7 @@ public SpeakerPlayClientMessage( UUID source, Vec3 pos, ResourceLocation event, public SpeakerPlayClientMessage( FriendlyByteBuf buf ) { source = buf.readUUID(); - pos = new Vec3( buf.readDouble(), buf.readDouble(), buf.readDouble() ); + pos = SpeakerPosition.Message.read( buf ); sound = buf.readResourceLocation(); volume = buf.readFloat(); pitch = buf.readFloat(); @@ -54,9 +54,7 @@ public SpeakerPlayClientMessage( FriendlyByteBuf buf ) public void toBytes( @Nonnull FriendlyByteBuf buf ) { buf.writeUUID( source ); - buf.writeDouble( pos.x() ); - buf.writeDouble( pos.y() ); - buf.writeDouble( pos.z() ); + pos.write( buf ); buf.writeResourceLocation( sound ); buf.writeFloat( volume ); buf.writeFloat( pitch ); @@ -66,6 +64,6 @@ public void toBytes( @Nonnull FriendlyByteBuf buf ) @Environment( EnvType.CLIENT ) public void handle( PacketContext context ) { - SpeakerManager.getSound( source ).playSound( pos, sound, volume, pitch ); + SpeakerManager.getSound( source ).playSound( pos.reify(), sound, volume, pitch ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java index 82dddab27..a529cc89c 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java @@ -5,7 +5,8 @@ */ package dan200.computercraft.shared.network.container; -import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; +import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; +import net.minecraft.core.Registry; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.MenuProvider; @@ -40,21 +41,21 @@ interface FixedFactory C create( MenuType type, int id, @Nonnull Inventory inventory, T data ); } - static MenuType toType( ResourceLocation identifier, Function reader, - Factory factory ) + static MenuType toType( + ResourceLocation identifier, Function reader, Factory factory + ) { - return ScreenHandlerRegistry.registerExtended( identifier, - ( id, playerInventory, packetByteBuf ) -> factory.create( id, - playerInventory, - reader.apply( packetByteBuf ) ) ); + return Registry.register( Registry.MENU, identifier, new ExtendedScreenHandlerType<>( ( id, playerInventory, packetByteBuf ) -> + factory.create( id, playerInventory, reader.apply( packetByteBuf ) ) + ) ); } - static MenuType toType( ResourceLocation identifier, MenuType type, Function reader, - FixedFactory factory ) + static MenuType toType( + ResourceLocation identifier, MenuType type, Function reader, FixedFactory factory + ) { - return ScreenHandlerRegistry.registerExtended( identifier, - ( id, playerInventory, packetByteBuf ) -> factory.create( type, id, - playerInventory, - reader.apply( packetByteBuf ) ) ); + return Registry.register( Registry.MENU, identifier, new ExtendedScreenHandlerType<>( ( id, playerInventory, packetByteBuf ) -> + factory.create( type, id, playerInventory, reader.apply( packetByteBuf ) ) + ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java b/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java index 04edcd2f8..27e557760 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java @@ -160,6 +160,7 @@ public static void send( int instanceId, List files ) contents.position( currentOffset ).limit( currentOffset + canWrite ); slices.add( new FileSlice( fileId, currentOffset, contents.slice() ) ); currentOffset += canWrite; + remaining -= canWrite; } contents.position( 0 ).limit( capacity ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java index 54a57e494..8a630f9f2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java @@ -12,9 +12,9 @@ import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IDynamicPeripheral; import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.core.Registry; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java index 63f2bdf88..ee8389c58 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java @@ -26,6 +26,7 @@ public static > T fill( @Nonnull T data, @ stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) ); } data.put( "state", stateTable ); + data.put( "tags", DataHelpers.getTags( state.getTags() ) ); return data; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java index 2c280fce6..bb0a51c59 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java @@ -5,44 +5,34 @@ */ package dan200.computercraft.shared.peripheral.generic.data; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.level.block.Block; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Collection; -import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; public final class DataHelpers { private DataHelpers() {} - @Nonnull - public static Map getTags( @Nonnull Collection tags ) - { - Map result = new HashMap<>( tags.size() ); - for( ResourceLocation location : tags ) result.put( location.toString(), true ); - return result; - } - - @Nonnull - static Map getTags( @Nonnull Block block ) + public static Map getTags( Holder.Reference object ) { - Collection tags = block.builtInRegistryHolder().tags().map( tag -> tag.location() ).collect( Collectors.toList() ); - return getTags( tags ); + return getTags( object.tags() ); } @Nonnull - static Map getTags( @Nonnull Item item ) + public static Map getTags( @Nonnull Stream> tags ) { - Collection tags = item.builtInRegistryHolder().tags().map( tag -> tag.location() ).collect( Collectors.toList() ); - return getTags( tags ); + return tags.collect( Collectors.toMap( x -> x.location().toString(), x -> true ) ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index 604521165..85ae8fade 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -65,7 +65,7 @@ public static > T fill( @Nonnull T data, @ data.put( "durability", stack.getItem().getBarWidth( stack ) / 13.0 ); } - data.put( "tags", DataHelpers.getTags( stack.getItem() ) ); + data.put( "tags", DataHelpers.getTags( stack.getTags() ) ); CompoundTag tag = stack.getTag(); if( tag != null && tag.contains( "display", Tag.TAG_COMPOUND ) ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 9ea45aba5..295e3776d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -166,7 +166,8 @@ public static int size( Container inventory ) @LuaFunction( mainThread = true ) public static int getItemLimit( Container inventory, int slot ) throws LuaException { - assertBetween( slot, 1, inventory.getContainerSize(), "Slot out of range (%s)" ); + ItemStorage itemStorage = extractHandler( inventory ); + assertBetween( slot, 1, itemStorage.size(), "Slot out of range (%s)" ); return inventory.getMaxStackSize(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 11d6e88a3..068e56bd2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -54,8 +54,7 @@ public Level getLevel() @Override public Vec3 getPosition() { - BlockPos pos = getBlockPos(); - return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return Vec3.atCenterOf( getBlockPos() ); } @Override @@ -97,8 +96,7 @@ protected WiredModemLocalPeripheral getLocalPeripheral() @Override public Vec3 getPosition() { - BlockPos pos = getBlockPos().relative( getDirection() ); - return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return Vec3.atCenterOf( getBlockPos().relative( getDirection() ) ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 8c157a17a..b5dea9367 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -81,8 +81,7 @@ public Level getLevel() @Override public Vec3 getPosition() { - BlockPos pos = entity.getBlockPos(); - return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return Vec3.atCenterOf( entity.getBlockPos() ); } } @@ -388,8 +387,7 @@ protected WiredModemLocalPeripheral getLocalPeripheral() @Override public Vec3 getPosition() { - BlockPos pos = getBlockPos().relative( side ); - return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return Vec3.atCenterOf( getBlockPos().relative( side ) ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index eeabbf315..6db6a44f6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -44,8 +44,7 @@ public Level getLevel() @Override public Vec3 getPosition() { - BlockPos pos = entity.getBlockPos().relative( entity.getDirection() ); - return new Vec3( pos.getX(), pos.getY(), pos.getZ() ); + return Vec3.atLowerCornerOf( entity.getBlockPos().relative( entity.getDirection() ) ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index 456bc56cc..8dcf92c12 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -6,8 +6,8 @@ package dan200.computercraft.shared.peripheral.monitor; import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.VertexBuffer; +import dan200.computercraft.client.util.DirectBuffers; +import dan200.computercraft.client.util.DirectVertexBuffer; import dan200.computercraft.shared.common.ClientTerminal; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -32,7 +32,8 @@ public final class ClientMonitor extends ClientTerminal public int tboBuffer; public int tboTexture; - public VertexBuffer buffer; + public int tboUniform; + public DirectVertexBuffer buffer; public ClientMonitor( boolean colour, TileMonitor origin ) { @@ -63,15 +64,15 @@ public boolean createBuffer( MonitorRenderer renderer ) deleteBuffers(); - tboBuffer = GlStateManager._glGenBuffers(); - GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, tboBuffer ); - GL15.glBufferData( GL31.GL_TEXTURE_BUFFER, 0, GL15.GL_STATIC_DRAW ); + tboBuffer = DirectBuffers.createBuffer(); + DirectBuffers.setEmptyBufferData( GL31.GL_TEXTURE_BUFFER, tboBuffer, GL15.GL_STATIC_DRAW ); tboTexture = GlStateManager._genTexture(); GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, tboTexture ); GL31.glTexBuffer( GL31.GL_TEXTURE_BUFFER, GL30.GL_R8UI, tboBuffer ); GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, 0 ); - GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 ); + tboUniform = DirectBuffers.createBuffer(); + DirectBuffers.setEmptyBufferData( GL31.GL_UNIFORM_BUFFER, tboUniform, GL15.GL_STATIC_DRAW ); addMonitor(); return true; @@ -81,7 +82,7 @@ public boolean createBuffer( MonitorRenderer renderer ) if( buffer != null ) return false; deleteBuffers(); - buffer = new VertexBuffer(); + buffer = new DirectVertexBuffer(); addMonitor(); return true; @@ -103,7 +104,7 @@ private void deleteBuffers() if( tboBuffer != 0 ) { - RenderSystem.glDeleteBuffers( tboBuffer ); + DirectBuffers.deleteBuffer( GL31.GL_TEXTURE_BUFFER, tboBuffer ); tboBuffer = 0; } @@ -113,6 +114,12 @@ private void deleteBuffers() tboTexture = 0; } + if( tboUniform != 0 ) + { + DirectBuffers.deleteBuffer( GL31.GL_UNIFORM_BUFFER, tboUniform ); + tboUniform = 0; + } + if( buffer != null ) { buffer.close(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java index 3eac19b1d..518ba2f54 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java @@ -8,6 +8,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.render.TileEntityMonitorRenderer; import net.fabricmc.loader.api.FabricLoader; +import org.lwjgl.opengl.GL; import javax.annotation.Nonnull; import java.util.Arrays; @@ -48,33 +49,32 @@ public enum MonitorRenderer @Nonnull public static MonitorRenderer current() { - if( !initialised ) initialise(); - MonitorRenderer current = ComputerCraft.monitorRenderer; - if( current == BEST ) return best(); + if( current == BEST ) current = ComputerCraft.monitorRenderer = best(); return current; } private static MonitorRenderer best() { + if( !GL.getCapabilities().OpenGL31 ) + { + ComputerCraft.log.warn( "Texture buffers are not supported on your graphics card. Falling back to VBO monitor renderer." ); + return VBO; + } + if( shaderMod ) { - ComputerCraft.log.warn( "Shader mod detected. Enabling VBO monitor renderer for compatibility." ); - return ComputerCraft.monitorRenderer = VBO; + ComputerCraft.log.warn( "Shader mod detected. Falling back to VBO monitor renderer." ); + return VBO; } - return ComputerCraft.monitorRenderer = TBO; + + return TBO; } - private static boolean initialised = false; - private static boolean shaderMod; private static final List shaderModIds = Arrays.asList( "iris", "canvas", "optifabric" ); + private static boolean shaderMod = FabricLoader.getInstance().getAllMods().stream() + .map( modContainer -> modContainer.getMetadata().getId() ) + .anyMatch( shaderModIds::contains ); - private static void initialise() - { - shaderMod = FabricLoader.getInstance().getAllMods().stream() - .map( modContainer -> modContainer.getMetadata().getId() ) - .anyMatch( shaderModIds::contains ); - - initialised = true; - } + public static final boolean canvasModPresent = FabricLoader.getInstance().isModLoaded( "canvas" ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index bcb90642c..c3ee14fde 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -25,8 +25,8 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; -import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -65,6 +65,11 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile private int xIndex = 0; private int yIndex = 0; + private BlockPos bbPos; + private BlockState bbState; + private int bbX, bbY, bbWidth, bbHeight; + private AABB boundingBox; + public TileMonitor( BlockEntityType type, BlockPos pos, BlockState state, boolean advanced ) { super( type, pos, state ); @@ -188,7 +193,7 @@ public void blockTick() @Nonnull @Override - public IPeripheral getPeripheral( @NotNull Direction side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { createServerMonitor(); // Ensure the monitor is created before doing anything else. if( peripheral == null ) peripheral = new MonitorPeripheral( this ); @@ -591,19 +596,34 @@ void removeComputer( IComputerAccess computer ) computers.remove( computer ); } - // @Nonnull - // @Override - // public AABB getRenderBoundingBox() - // { - // BlockPos startPos = toWorldPos( 0, 0 ); - // BlockPos endPos = toWorldPos( width, height ); - // return new AABB( - // Math.min( startPos.getX(), endPos.getX() ), - // Math.min( startPos.getY(), endPos.getY() ), - // Math.min( startPos.getZ(), endPos.getZ() ), - // Math.max( startPos.getX(), endPos.getX() ) + 1, - // Math.max( startPos.getY(), endPos.getY() ) + 1, - // Math.max( startPos.getZ(), endPos.getZ() ) + 1 - // ); - // } + @Nonnull + public AABB getRenderBoundingBox() + { + // We attempt to cache the bounding box to save having to do property lookups (and allocations!) on every frame. + // Unfortunately the AABB does depend on quite a lot of state, so we need to add a bunch of extra fields - + // ideally these'd be a single object, but I don't think worth doing until Java has value types. + if( boundingBox != null && getBlockState().equals( bbState ) && getBlockPos().equals( bbPos ) && + xIndex == bbX && yIndex == bbY && width == bbWidth && height == bbHeight ) + { + return boundingBox; + } + + bbState = getBlockState(); + bbPos = getBlockPos(); + bbX = xIndex; + bbY = yIndex; + bbWidth = width; + bbHeight = height; + + BlockPos startPos = toWorldPos( 0, 0 ); + BlockPos endPos = toWorldPos( width, height ); + return boundingBox = new AABB( + Math.min( startPos.getX(), endPos.getX() ), + Math.min( startPos.getY(), endPos.getY() ), + Math.min( startPos.getZ(), endPos.getZ() ), + Math.max( startPos.getX(), endPos.getX() ) + 1, + Math.max( startPos.getY(), endPos.getY() ) + 1, + Math.max( startPos.getZ(), endPos.getZ() ) + 1 + ); + } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 41d8a27a1..42b912776 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -10,7 +10,9 @@ import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.media.items.ItemPrintout; -import dan200.computercraft.shared.util.*; +import dan200.computercraft.shared.util.ColourUtils; +import dan200.computercraft.shared.util.DefaultSidedInventory; +import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index b2a032464..cf6bb6aa9 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -29,7 +29,6 @@ import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.util.*; import static dan200.computercraft.api.lua.LuaValues.checkFinite; @@ -57,7 +56,7 @@ public abstract class SpeakerPeripheral implements IPeripheral private long clock = 0; private long lastPositionTime; - private Vec3 lastPosition; + private SpeakerPosition lastPosition; private long lastPlayTime; @@ -72,8 +71,9 @@ public void update() { clock++; - Vec3 pos = getPosition(); - Level level = getLevel(); + SpeakerPosition position = getPosition(); + Level level = position.level(); + Vec3 pos = position.position(); if( level == null ) return; MinecraftServer server = level.getServer(); @@ -125,20 +125,20 @@ public void update() { lastPlayTime = clock; NetworkHandler.sendToAllAround( - new SpeakerPlayClientMessage( getSource(), pos, sound.location, sound.volume, sound.pitch ), + new SpeakerPlayClientMessage( getSource(), position, sound.location, sound.volume, sound.pitch ), level, pos, sound.volume * 16 ); - syncedPosition( pos ); + syncedPosition( position ); } else if( dfpwmState != null && dfpwmState.shouldSendPending( now ) ) { // If clients need to receive another batch of audio, send it and then notify computers our internal buffer is // free again. NetworkHandler.sendToAllTracking( - new SpeakerAudioClientMessage( getSource(), pos, dfpwmState.getVolume(), dfpwmState.pullPending( now ) ), - getLevel().getChunkAt( new BlockPos( pos ) ) + new SpeakerAudioClientMessage( getSource(), position, dfpwmState.getVolume(), dfpwmState.pullPending( now ) ), + level.getChunkAt( new BlockPos( pos ) ) ); - syncedPosition( pos ); + syncedPosition( position ); // And notify computers that we have space for more audio. synchronized( computers ) @@ -153,25 +153,19 @@ else if( dfpwmState != null && dfpwmState.shouldSendPending( now ) ) // Push position updates to any speakers which have ever played a note, // have moved by a non-trivial amount and haven't had a position update // in the last second. - if( lastPosition != null && (clock - lastPositionTime) >= 20 ) + if( lastPosition != null && (clock - lastPositionTime) >= 20 && !lastPosition.withinDistance( position, 0.1 ) ) { - Vec3 position = getPosition(); - if( lastPosition.distanceToSqr( position ) >= 0.1 ) - { - NetworkHandler.sendToAllTracking( - new SpeakerMoveClientMessage( getSource(), position ), - getLevel().getChunkAt( new BlockPos( position ) ) - ); - syncedPosition( position ); - } + // TODO: What to do when entities move away? How do we notify people left behind that they're gone. + NetworkHandler.sendToAllTracking( + new SpeakerMoveClientMessage( getSource(), position ), + level.getChunkAt( new BlockPos( pos ) ) + ); + syncedPosition( position ); } } - @Nullable - public abstract Level getLevel(); - @Nonnull - public abstract Vec3 getPosition(); + public abstract SpeakerPosition getPosition(); @Nonnull public UUID getSource() @@ -373,7 +367,7 @@ public final void stop() shouldStop = true; } - private void syncedPosition( Vec3 position ) + private void syncedPosition( SpeakerPosition position ) { lastPosition = position; lastPositionTime = clock; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPosition.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPosition.java new file mode 100644 index 000000000..207869b89 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPosition.java @@ -0,0 +1,91 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.peripheral.speaker; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.OptionalInt; + +public record SpeakerPosition(@Nullable Level level, @Nonnull Vec3 position, @Nullable Entity entity) +{ + public static SpeakerPosition of( @Nullable Level level, @Nonnull Vec3 position ) + { + return new SpeakerPosition( level, position, null ); + } + + public static SpeakerPosition of( @Nonnull Entity entity ) + { + return new SpeakerPosition( entity.level, entity.getEyePosition( 1 ), entity ); + } + + public boolean withinDistance( SpeakerPosition other, double distanceSq ) + { + return level == other.level && entity == other.entity && position.distanceToSqr( other.position ) <= distanceSq; + } + + public Message asMessage() + { + if( level == null ) throw new NullPointerException( "Cannot send a position without a level" ); + return new Message( level.dimension().location(), position, entity == null ? OptionalInt.empty() : OptionalInt.of( entity.getId() ) ); + } + + public static final class Message + { + private final ResourceLocation level; + private final Vec3 position; + private final OptionalInt entity; + + private Message( ResourceLocation level, Vec3 position, OptionalInt entity ) + { + this.level = level; + this.position = position; + this.entity = entity; + } + + public static Message read( @Nonnull FriendlyByteBuf buffer ) + { + ResourceLocation level = buffer.readResourceLocation(); + Vec3 position = new Vec3( buffer.readDouble(), buffer.readDouble(), buffer.readDouble() ); + OptionalInt entity = buffer.readBoolean() ? OptionalInt.of( buffer.readInt() ) : OptionalInt.empty(); + return new Message( level, position, entity ); + } + + public void write( @Nonnull FriendlyByteBuf buffer ) + { + buffer.writeResourceLocation( level ); + + buffer.writeDouble( position.x ); + buffer.writeDouble( position.y ); + buffer.writeDouble( position.z ); + + buffer.writeBoolean( entity.isPresent() ); + if( entity.isPresent() ) buffer.writeInt( entity.getAsInt() ); + } + + @Nonnull + @Environment( EnvType.CLIENT ) + public SpeakerPosition reify() + { + Minecraft minecraft = Minecraft.getInstance(); + Level level = minecraft.level; + if( level != null && !level.dimension().location().equals( this.level ) ) level = null; + + return new SpeakerPosition( + level, position, + level != null && entity.isPresent() ? level.getEntity( entity.getAsInt() ) : null + ); + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index 01f1e18a2..8460da970 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -12,7 +12,6 @@ import dan200.computercraft.shared.network.client.SpeakerStopClientMessage; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -63,18 +62,11 @@ private Peripheral( TileSpeaker speaker ) this.speaker = speaker; } - @Override - public Level getLevel() - { - return speaker.getLevel(); - } - @Nonnull @Override - public Vec3 getPosition() + public SpeakerPosition getPosition() { - BlockPos pos = speaker.getBlockPos(); - return new Vec3( pos.getX(), pos.getY(), pos.getZ() ); + return SpeakerPosition.of( speaker.getLevel(), Vec3.atCenterOf( speaker.getBlockPos() ) ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index 374bb1f23..f47b2efb9 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -21,6 +21,7 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; @@ -60,6 +61,10 @@ else if( entity instanceof LivingEntity living ) { return living.getMainHandItem() == stack || living.getOffhandItem() == stack ? entity : null; } + else if( entity instanceof ItemEntity itemEntity ) + { + return itemEntity.getItem() == stack ? entity : null; + } else { return null; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java index 959cfcca6..d18630336 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java @@ -10,7 +10,6 @@ import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; import javax.annotation.Nonnull; @@ -27,21 +26,13 @@ public PocketSpeaker( ResourceLocation id, ItemStack item ) @Override public IPeripheral createPeripheral( @Nonnull IPocketAccess access ) { - return new PocketSpeakerPeripheral(); + return new PocketSpeakerPeripheral( access ); } @Override public void update( @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral ) { - if( !(peripheral instanceof PocketSpeakerPeripheral speaker) ) return; - - Entity entity = access.getEntity(); - if( entity != null ) - { - speaker.setLocation( entity.getCommandSenderWorld(), entity.getEyePosition( 1 ) ); - } - - speaker.update(); - access.setLight( speaker.madeSound() ? 0x3320fc : -1 ); + if( !(peripheral instanceof PocketSpeakerPeripheral) ) return; + ((PocketSpeakerPeripheral) peripheral).update(); } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java index 38869fda4..ed28046ac 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java @@ -6,7 +6,10 @@ package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -14,31 +17,41 @@ public class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral { - private Level world = null; + private final IPocketAccess access; + private Level level; private Vec3 position = Vec3.ZERO; - void setLocation( Level world, Vec3 position ) + public PocketSpeakerPeripheral( IPocketAccess access ) { - this.position = position; - this.world = world; + this.access = access; } + @Nonnull @Override - public Level getLevel() + public SpeakerPosition getPosition() { - return world; + Entity entity = access.getEntity(); + return entity == null ? SpeakerPosition.of( level, position ) : SpeakerPosition.of( entity ); } - @Nonnull @Override - public Vec3 getPosition() + public boolean equals( IPeripheral other ) { - return world != null ? position : null; + return other instanceof PocketSpeakerPeripheral; } @Override - public boolean equals( IPeripheral other ) + public void update() { - return other instanceof PocketSpeakerPeripheral; + Entity entity = access.getEntity(); + if( entity != null ) + { + level = entity.level; + position = entity.position(); + } + + super.update(); + + access.setLight( madeSound() ? 0x3320fc : -1 ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 481ae91c9..fd13fe0c9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -66,6 +66,7 @@ * accessible by accessing the `"left"` or `"right"` peripheral. * * [Turtle Graphics]: https://en.wikipedia.org/wiki/Turtle_graphics "Turtle graphics" + * * @cc.module turtle * @cc.since 1.3 */ diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index e9bf0fa72..85feeb6ee 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -432,10 +432,13 @@ public ItemStack removeItem( int slot, int count ) @Override public void setItem( int i, @Nonnull ItemStack stack ) { - if( i >= 0 && i < INVENTORY_SIZE && !InventoryUtil.areItemsEqual( stack, inventory.get( i ) ) ) + if ( i >= 0 && i < INVENTORY_SIZE ) { inventory.set( i, stack ); - onInventoryDefinitelyChanged(); + if ( !InventoryUtil.areItemsEqual( stack, inventory.get( i ) ) ) + { + onInventoryDefinitelyChanged(); + } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 9745f74a8..56c37f59f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -11,7 +11,10 @@ import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.TurtlePermissions; -import dan200.computercraft.shared.util.*; +import dan200.computercraft.shared.util.DropConsumer; +import dan200.computercraft.shared.util.InventoryUtil; +import dan200.computercraft.shared.util.ItemStorage; +import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.chat.TextComponent; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 269b73616..f30df1817 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -9,7 +9,6 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.ITurtleAccess; -import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; @@ -23,7 +22,6 @@ import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityDimensions; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Pose; import net.minecraft.world.entity.animal.horse.AbstractHorse; import net.minecraft.world.item.ItemStack; @@ -197,13 +195,6 @@ public void unloadInventory( ITurtleAccess turtle ) getInventory().setChanged(); } - @Nonnull - @Override - public EntityType getType() - { - return Registry.ModEntities.TURTLE_PLAYER; - } - @Override public Vec3 position() { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index 59f5c22d2..ccd33ca88 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -11,14 +11,13 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; +import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.resources.model.ModelResourceLocation; -import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; @@ -41,18 +40,11 @@ private static class Peripheral extends UpgradeSpeakerPeripheral this.turtle = turtle; } - @Override - public Level getLevel() - { - return turtle.getLevel(); - } - @Nonnull @Override - public Vec3 getPosition() + public SpeakerPosition getPosition() { - BlockPos pos = turtle.getPosition(); - return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return SpeakerPosition.of( turtle.getLevel(), Vec3.atCenterOf( turtle.getPosition() ) ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java index 9a8480852..8fe407c8f 100644 --- a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java +++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java @@ -285,7 +285,7 @@ private static class FakeNetworkManager extends Connection FakeNetworkManager() { super( PacketFlow.CLIENTBOUND ); - ((ConnectionAccess)this).setChannel( new EmbeddedChannel() ); + ((ConnectionAccess) this).setChannel( new EmbeddedChannel() ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index e1f7be027..00c780e04 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -46,21 +46,17 @@ public static File getDir() return GameInstanceUtils.getServer().getWorldPath( FOLDER ).toFile(); } - private static MinecraftServer getCachedServer() + private static boolean hasServerChanged() { - if( server == null ) return null; + if( server == null ) return true; MinecraftServer currentServer = server.get(); - if( currentServer == null ) return null; - - if( currentServer != GameInstanceUtils.getServer() ) return null; - return currentServer; + return currentServer == null || currentServer != GameInstanceUtils.getServer(); } public static synchronized int getNextId( String kind ) { - MinecraftServer currentServer = getCachedServer(); - if( currentServer == null ) + if( hasServerChanged() ) { // The server has changed, refetch our ID map server = new WeakReference<>( GameInstanceUtils.getServer() ); @@ -69,23 +65,22 @@ public static synchronized int getNextId( String kind ) dir.mkdirs(); // Load our ID file from disk + Map newIds = null; idFile = new File( dir, "ids.json" ).toPath(); if( Files.isRegularFile( idFile ) ) { try( Reader reader = Files.newBufferedReader( idFile, StandardCharsets.UTF_8 ) ) { - ids = GSON.fromJson( reader, ID_TOKEN ); + newIds = GSON.fromJson( reader, ID_TOKEN ); } catch( Exception e ) { ComputerCraft.log.error( "Cannot load id file '" + idFile + "'", e ); - ids = new HashMap<>(); } } - else - { - ids = new HashMap<>(); - } + + if( newIds == null ) newIds = new HashMap<>(); + ids = newIds; } Integer existing = ids.get( kind ); diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index f5343726f..6f4900300 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -5,13 +5,18 @@ */ package dan200.computercraft.shared.util; +import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; +import javax.annotation.Nonnull; + public class Palette { private static final int PALETTE_SIZE = 16; private final double[][] colours = new double[PALETTE_SIZE][3]; + private final byte[][] byteColours = new byte[PALETTE_SIZE][4]; + private final byte[][] greyByteColours = new byte[PALETTE_SIZE][4]; public static final Palette DEFAULT = new Palette(); @@ -19,16 +24,23 @@ public Palette() { // Get the default palette resetColours(); + + for( int i = 0; i < PALETTE_SIZE; i++ ) byteColours[i][3] = greyByteColours[i][3] = (byte) 255; } public void setColour( int i, double r, double g, double b ) { - if( i >= 0 && i < colours.length ) - { - colours[i][0] = r; - colours[i][1] = g; - colours[i][2] = b; - } + if( i < 0 || i >= colours.length ) return; + colours[i][0] = r; + colours[i][1] = g; + colours[i][2] = b; + + byteColours[i][0] = (byte) (int) (r * 255); + byteColours[i][1] = (byte) (int) (g * 255); + byteColours[i][2] = (byte) (int) (b * 255); + + byte grey = (byte) (int) ((r + g + b) / 3 * 255); + greyByteColours[i][0] = greyByteColours[i][1] = greyByteColours[i][2] = grey; } public void setColour( int i, Colour colour ) @@ -38,19 +50,29 @@ public void setColour( int i, Colour colour ) public double[] getColour( int i ) { - if( i >= 0 && i < colours.length ) - { - return colours[i]; - } - return null; + return i >= 0 && i < colours.length ? colours[i] : null; + } + + /** + * Get the colour as a set of bytes rather than floats. This is called frequently by {@link FixedWidthFontRenderer}, + * as our vertex format uses bytes. + * + * This allows us to do the conversion once (when setting the colour) rather than for every vertex, at the cost of + * some memory overhead. + * + * @param i The colour index. + * @param greyscale Whether this number should be converted to greyscale. + * @return The number as a tuple of bytes. + */ + @Nonnull + public byte[] getByteColour( int i, boolean greyscale ) + { + return greyscale ? greyByteColours[i] : byteColours[i]; } public void resetColour( int i ) { - if( i >= 0 && i < colours.length ) - { - setColour( i, Colour.VALUES[i] ); - } + if( i >= 0 && i < colours.length ) setColour( i, Colour.VALUES[i] ); } public void resetColours() @@ -89,9 +111,12 @@ public void write( FriendlyByteBuf buffer ) public void read( FriendlyByteBuf buffer ) { - for( double[] colour : colours ) + for( int i = 0; i < PALETTE_SIZE; i++ ) { - for( int i = 0; i < colour.length; i++ ) colour[i] = (buffer.readByte() & 0xFF) / 255.0; + double r = (buffer.readByte() & 0xFF) / 255.0; + double g = (buffer.readByte() & 0xFF) / 255.0; + double b = (buffer.readByte() & 0xFF) / 255.0; + setColour( i, r, g, b ); } } @@ -117,7 +142,8 @@ public void readFromNBT( CompoundTag nbt ) for( int i = 0; i < colours.length; i++ ) { - colours[i] = decodeRGB8( rgb8[i] ); + double[] colours = decodeRGB8( rgb8[i] ); + setColour( i, colours[0], colours[1], colours[2] ); } } } diff --git a/src/main/resources/assets/computercraft/blockstates/computer_advanced.json b/src/main/resources/assets/computercraft/blockstates/computer_advanced.json deleted file mode 100644 index f438720d8..000000000 --- a/src/main/resources/assets/computercraft/blockstates/computer_advanced.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "variants": { - "facing=north,state=off": { "model": "computercraft:block/computer_advanced_off" }, - "facing=south,state=off": { "model": "computercraft:block/computer_advanced_off", "y": 180 }, - "facing=west,state=off": { "model": "computercraft:block/computer_advanced_off", "y": 270 }, - "facing=east,state=off": { "model": "computercraft:block/computer_advanced_off", "y": 90 }, - - "facing=north,state=on": { "model": "computercraft:block/computer_advanced_on" }, - "facing=south,state=on": { "model": "computercraft:block/computer_advanced_on", "y": 180 }, - "facing=west,state=on": { "model": "computercraft:block/computer_advanced_on", "y": 270 }, - "facing=east,state=on": { "model": "computercraft:block/computer_advanced_on", "y": 90 }, - - "facing=north,state=blinking": { "model": "computercraft:block/computer_advanced_blinking" }, - "facing=south,state=blinking": { "model": "computercraft:block/computer_advanced_blinking", "y": 180 }, - "facing=west,state=blinking": { "model": "computercraft:block/computer_advanced_blinking", "y": 270 }, - "facing=east,state=blinking": { "model": "computercraft:block/computer_advanced_blinking", "y": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/computer_command.json b/src/main/resources/assets/computercraft/blockstates/computer_command.json deleted file mode 100644 index cb45d46c2..000000000 --- a/src/main/resources/assets/computercraft/blockstates/computer_command.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "variants": { - - "facing=north,state=off": { "model": "computercraft:block/computer_command_off" }, - "facing=south,state=off": { "model": "computercraft:block/computer_command_off", "y": 180 }, - "facing=west,state=off": { "model": "computercraft:block/computer_command_off", "y": 270 }, - "facing=east,state=off": { "model": "computercraft:block/computer_command_off", "y": 90 }, - - "facing=north,state=on": { "model": "computercraft:block/computer_command_on" }, - "facing=south,state=on": { "model": "computercraft:block/computer_command_on", "y": 180 }, - "facing=west,state=on": { "model": "computercraft:block/computer_command_on", "y": 270 }, - "facing=east,state=on": { "model": "computercraft:block/computer_command_on", "y": 90 }, - - "facing=north,state=blinking": { "model": "computercraft:block/computer_command_blinking" }, - "facing=south,state=blinking": { "model": "computercraft:block/computer_command_blinking", "y": 180 }, - "facing=west,state=blinking": { "model": "computercraft:block/computer_command_blinking", "y": 270 }, - "facing=east,state=blinking": { "model": "computercraft:block/computer_command_blinking", "y": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/computer_normal.json b/src/main/resources/assets/computercraft/blockstates/computer_normal.json deleted file mode 100644 index 95e521a7d..000000000 --- a/src/main/resources/assets/computercraft/blockstates/computer_normal.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "variants": { - "facing=north,state=off": { "model": "computercraft:block/computer_normal_off" }, - "facing=south,state=off": { "model": "computercraft:block/computer_normal_off", "y": 180 }, - "facing=west,state=off": { "model": "computercraft:block/computer_normal_off", "y": 270 }, - "facing=east,state=off": { "model": "computercraft:block/computer_normal_off", "y": 90 }, - - "facing=north,state=on": { "model": "computercraft:block/computer_normal_on" }, - "facing=south,state=on": { "model": "computercraft:block/computer_normal_on", "y": 180 }, - "facing=west,state=on": { "model": "computercraft:block/computer_normal_on", "y": 270 }, - "facing=east,state=on": { "model": "computercraft:block/computer_normal_on", "y": 90 }, - - "facing=north,state=blinking": { "model": "computercraft:block/computer_normal_blinking" }, - "facing=south,state=blinking": { "model": "computercraft:block/computer_normal_blinking", "y": 180 }, - "facing=west,state=blinking": { "model": "computercraft:block/computer_normal_blinking", "y": 270 }, - "facing=east,state=blinking": { "model": "computercraft:block/computer_normal_blinking", "y": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/monitor_advanced.json b/src/main/resources/assets/computercraft/blockstates/monitor_advanced.json deleted file mode 100644 index b55870f67..000000000 --- a/src/main/resources/assets/computercraft/blockstates/monitor_advanced.json +++ /dev/null @@ -1,364 +0,0 @@ -{ - "variants": { - "facing=north,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced" }, - "facing=south,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced", "y": 180 }, - "facing=west,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced", "y": 270 }, - "facing=east,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced", "y": 90 }, - "facing=north,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r" }, - "facing=south,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 180 }, - "facing=west,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 270 }, - "facing=east,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 90 }, - "facing=north,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr" }, - "facing=south,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "y": 180 }, - "facing=west,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "y": 270 }, - "facing=east,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "y": 90 }, - "facing=north,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l" }, - "facing=south,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 180 }, - "facing=west,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 270 }, - "facing=east,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 90 }, - "facing=north,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d" }, - "facing=south,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 180 }, - "facing=west,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 270 }, - "facing=east,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 90 }, - "facing=north,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud" }, - "facing=south,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "y": 180 }, - "facing=west,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "y": 270 }, - "facing=east,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "y": 90 }, - "facing=north,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u" }, - "facing=south,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 180 }, - "facing=west,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 270 }, - "facing=east,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 90 }, - "facing=north,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd" }, - "facing=south,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "y": 180 }, - "facing=west,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "y": 270 }, - "facing=east,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "y": 90 }, - "facing=north,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd" }, - "facing=south,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "y": 180 }, - "facing=west,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "y": 270 }, - "facing=east,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "y": 90 }, - "facing=north,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld" }, - "facing=south,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "y": 180 }, - "facing=west,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "y": 270 }, - "facing=east,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "y": 90 }, - "facing=north,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud" }, - "facing=south,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "y": 180 }, - "facing=west,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "y": 270 }, - "facing=east,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "y": 90 }, - "facing=north,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud" }, - "facing=south,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "y": 180 }, - "facing=west,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "y": 270 }, - "facing=east,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "y": 90 }, - "facing=north,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud" }, - "facing=south,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "y": 180 }, - "facing=west,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "y": 270 }, - "facing=east,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "y": 90 }, - "facing=north,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru" }, - "facing=south,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "y": 180 }, - "facing=west,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "y": 270 }, - "facing=east,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "y": 90 }, - "facing=north,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru" }, - "facing=south,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "y": 180 }, - "facing=west,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "y": 270 }, - "facing=east,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "y": 90 }, - "facing=north,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu" }, - "facing=south,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "y": 180 }, - "facing=west,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "y": 270 }, - "facing=east,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "y": 90 }, - - "facing=north,orientation=up,state=none": { "model": "computercraft:block/monitor_advanced", "x": 270 }, - "facing=south,orientation=up,state=none": { - "model": "computercraft:block/monitor_advanced", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=none": { - "model": "computercraft:block/monitor_advanced", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=none": { "model": "computercraft:block/monitor_advanced", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=r": { "model": "computercraft:block/monitor_advanced_r", "x": 270 }, - "facing=south,orientation=up,state=r": { - "model": "computercraft:block/monitor_advanced_r", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "x": 270 }, - "facing=south,orientation=up,state=lr": { - "model": "computercraft:block/monitor_advanced_lr", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lr": { - "model": "computercraft:block/monitor_advanced_lr", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lr": { - "model": "computercraft:block/monitor_advanced_lr", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=l": { "model": "computercraft:block/monitor_advanced_l", "x": 270 }, - "facing=south,orientation=up,state=l": { - "model": "computercraft:block/monitor_advanced_l", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=d": { "model": "computercraft:block/monitor_advanced_d", "x": 270 }, - "facing=south,orientation=up,state=d": { - "model": "computercraft:block/monitor_advanced_d", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "x": 270 }, - "facing=south,orientation=up,state=ud": { - "model": "computercraft:block/monitor_advanced_ud", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=ud": { - "model": "computercraft:block/monitor_advanced_ud", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=ud": { - "model": "computercraft:block/monitor_advanced_ud", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=u": { "model": "computercraft:block/monitor_advanced_u", "x": 270 }, - "facing=south,orientation=up,state=u": { - "model": "computercraft:block/monitor_advanced_u", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "x": 270 }, - "facing=south,orientation=up,state=rd": { - "model": "computercraft:block/monitor_advanced_rd", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=rd": { - "model": "computercraft:block/monitor_advanced_rd", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=rd": { - "model": "computercraft:block/monitor_advanced_rd", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "x": 270 }, - "facing=south,orientation=up,state=lrd": { - "model": "computercraft:block/monitor_advanced_lrd", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lrd": { - "model": "computercraft:block/monitor_advanced_lrd", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lrd": { - "model": "computercraft:block/monitor_advanced_lrd", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "x": 270 }, - "facing=south,orientation=up,state=ld": { - "model": "computercraft:block/monitor_advanced_ld", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=ld": { - "model": "computercraft:block/monitor_advanced_ld", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=ld": { - "model": "computercraft:block/monitor_advanced_ld", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "x": 270 }, - "facing=south,orientation=up,state=rud": { - "model": "computercraft:block/monitor_advanced_rud", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=rud": { - "model": "computercraft:block/monitor_advanced_rud", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=rud": { - "model": "computercraft:block/monitor_advanced_rud", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "x": 270 }, - "facing=south,orientation=up,state=lrud": { - "model": "computercraft:block/monitor_advanced_lrud", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lrud": { - "model": "computercraft:block/monitor_advanced_lrud", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lrud": { - "model": "computercraft:block/monitor_advanced_lrud", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "x": 270 }, - "facing=south,orientation=up,state=lud": { - "model": "computercraft:block/monitor_advanced_lud", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lud": { - "model": "computercraft:block/monitor_advanced_lud", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lud": { - "model": "computercraft:block/monitor_advanced_lud", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "x": 270 }, - "facing=south,orientation=up,state=ru": { - "model": "computercraft:block/monitor_advanced_ru", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=ru": { - "model": "computercraft:block/monitor_advanced_ru", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=ru": { - "model": "computercraft:block/monitor_advanced_ru", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "x": 270 }, - "facing=south,orientation=up,state=lru": { - "model": "computercraft:block/monitor_advanced_lru", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lru": { - "model": "computercraft:block/monitor_advanced_lru", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lru": { - "model": "computercraft:block/monitor_advanced_lru", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "x": 270 }, - "facing=south,orientation=up,state=lu": { - "model": "computercraft:block/monitor_advanced_lu", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lu": { - "model": "computercraft:block/monitor_advanced_lu", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lu": { - "model": "computercraft:block/monitor_advanced_lu", "y": 90, "x": 270 - }, - - "facing=north,orientation=down,state=none": { "model": "computercraft:block/monitor_advanced", "x": 90 }, - "facing=south,orientation=down,state=none": { - "model": "computercraft:block/monitor_advanced", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=none": { - "model": "computercraft:block/monitor_advanced", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=none": { - "model": "computercraft:block/monitor_advanced", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=r": { "model": "computercraft:block/monitor_advanced_r", "x": 90 }, - "facing=south,orientation=down,state=r": { - "model": "computercraft:block/monitor_advanced_r", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=r": { - "model": "computercraft:block/monitor_advanced_r", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "x": 90 }, - "facing=south,orientation=down,state=lr": { - "model": "computercraft:block/monitor_advanced_lr", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lr": { - "model": "computercraft:block/monitor_advanced_lr", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lr": { - "model": "computercraft:block/monitor_advanced_lr", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=l": { "model": "computercraft:block/monitor_advanced_l", "x": 90 }, - "facing=south,orientation=down,state=l": { - "model": "computercraft:block/monitor_advanced_l", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=l": { - "model": "computercraft:block/monitor_advanced_l", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=d": { "model": "computercraft:block/monitor_advanced_d", "x": 90 }, - "facing=south,orientation=down,state=d": { - "model": "computercraft:block/monitor_advanced_d", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=d": { - "model": "computercraft:block/monitor_advanced_d", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "x": 90 }, - "facing=south,orientation=down,state=ud": { - "model": "computercraft:block/monitor_advanced_ud", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=ud": { - "model": "computercraft:block/monitor_advanced_ud", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=ud": { - "model": "computercraft:block/monitor_advanced_ud", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=u": { "model": "computercraft:block/monitor_advanced_u", "x": 90 }, - "facing=south,orientation=down,state=u": { - "model": "computercraft:block/monitor_advanced_u", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=u": { - "model": "computercraft:block/monitor_advanced_u", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "x": 90 }, - "facing=south,orientation=down,state=rd": { - "model": "computercraft:block/monitor_advanced_rd", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=rd": { - "model": "computercraft:block/monitor_advanced_rd", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=rd": { - "model": "computercraft:block/monitor_advanced_rd", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "x": 90 }, - "facing=south,orientation=down,state=lrd": { - "model": "computercraft:block/monitor_advanced_lrd", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lrd": { - "model": "computercraft:block/monitor_advanced_lrd", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lrd": { - "model": "computercraft:block/monitor_advanced_lrd", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "x": 90 }, - "facing=south,orientation=down,state=ld": { - "model": "computercraft:block/monitor_advanced_ld", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=ld": { - "model": "computercraft:block/monitor_advanced_ld", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=ld": { - "model": "computercraft:block/monitor_advanced_ld", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "x": 90 }, - "facing=south,orientation=down,state=rud": { - "model": "computercraft:block/monitor_advanced_rud", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=rud": { - "model": "computercraft:block/monitor_advanced_rud", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=rud": { - "model": "computercraft:block/monitor_advanced_rud", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "x": 90 }, - "facing=south,orientation=down,state=lrud": { - "model": "computercraft:block/monitor_advanced_lrud", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lrud": { - "model": "computercraft:block/monitor_advanced_lrud", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lrud": { - "model": "computercraft:block/monitor_advanced_lrud", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "x": 90 }, - "facing=south,orientation=down,state=lud": { - "model": "computercraft:block/monitor_advanced_lud", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lud": { - "model": "computercraft:block/monitor_advanced_lud", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lud": { - "model": "computercraft:block/monitor_advanced_lud", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "x": 90 }, - "facing=south,orientation=down,state=ru": { - "model": "computercraft:block/monitor_advanced_ru", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=ru": { - "model": "computercraft:block/monitor_advanced_ru", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=ru": { - "model": "computercraft:block/monitor_advanced_ru", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "x": 90 }, - "facing=south,orientation=down,state=lru": { - "model": "computercraft:block/monitor_advanced_lru", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lru": { - "model": "computercraft:block/monitor_advanced_lru", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lru": { - "model": "computercraft:block/monitor_advanced_lru", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "x": 90 }, - "facing=south,orientation=down,state=lu": { - "model": "computercraft:block/monitor_advanced_lu", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lu": { - "model": "computercraft:block/monitor_advanced_lu", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lu": { - "model": "computercraft:block/monitor_advanced_lu", "y": 90, "x": 90 - } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/monitor_normal.json b/src/main/resources/assets/computercraft/blockstates/monitor_normal.json deleted file mode 100644 index b14a45a21..000000000 --- a/src/main/resources/assets/computercraft/blockstates/monitor_normal.json +++ /dev/null @@ -1,296 +0,0 @@ -{ - "variants": { - "facing=north,orientation=north,state=none": { "model": "computercraft:block/monitor_normal" }, - "facing=south,orientation=north,state=none": { "model": "computercraft:block/monitor_normal", "y": 180 }, - "facing=west,orientation=north,state=none": { "model": "computercraft:block/monitor_normal", "y": 270 }, - "facing=east,orientation=north,state=none": { "model": "computercraft:block/monitor_normal", "y": 90 }, - "facing=north,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r" }, - "facing=south,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 180 }, - "facing=west,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 270 }, - "facing=east,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 90 }, - "facing=north,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr" }, - "facing=south,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 180 }, - "facing=west,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 270 }, - "facing=east,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 90 }, - "facing=north,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l" }, - "facing=south,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 180 }, - "facing=west,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 270 }, - "facing=east,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 90 }, - "facing=north,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d" }, - "facing=south,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 180 }, - "facing=west,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 270 }, - "facing=east,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 90 }, - "facing=north,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud" }, - "facing=south,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 180 }, - "facing=west,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 270 }, - "facing=east,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 90 }, - "facing=north,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u" }, - "facing=south,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 180 }, - "facing=west,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 270 }, - "facing=east,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 90 }, - "facing=north,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd" }, - "facing=south,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 180 }, - "facing=west,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 270 }, - "facing=east,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 90 }, - "facing=north,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd" }, - "facing=south,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "y": 180 }, - "facing=west,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "y": 270 }, - "facing=east,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "y": 90 }, - "facing=north,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld" }, - "facing=south,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 180 }, - "facing=west,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 270 }, - "facing=east,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 90 }, - "facing=north,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud" }, - "facing=south,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud", "y": 180 }, - "facing=west,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud", "y": 270 }, - "facing=east,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud", "y": 90 }, - "facing=north,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud" }, - "facing=south,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "y": 180 }, - "facing=west,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "y": 270 }, - "facing=east,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "y": 90 }, - "facing=north,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud" }, - "facing=south,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud", "y": 180 }, - "facing=west,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud", "y": 270 }, - "facing=east,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud", "y": 90 }, - "facing=north,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru" }, - "facing=south,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 180 }, - "facing=west,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 270 }, - "facing=east,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 90 }, - "facing=north,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru" }, - "facing=south,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru", "y": 180 }, - "facing=west,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru", "y": 270 }, - "facing=east,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru", "y": 90 }, - "facing=north,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu" }, - "facing=south,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 180 }, - "facing=west,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 270 }, - "facing=east,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 90 }, - - "facing=north,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "x": 270 }, - "facing=south,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "y": 180, "x": 270 }, - "facing=west,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "x": 270 }, - "facing=south,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 180, "x": 270 }, - "facing=west,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=lr": { "model": "computercraft:block/monitor_normal_lr", "x": 270 }, - "facing=south,orientation=up,state=lr": { - "model": "computercraft:block/monitor_normal_lr", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "x": 270 }, - "facing=south,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 180, "x": 270 }, - "facing=west,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "x": 270 }, - "facing=south,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 180, "x": 270 }, - "facing=west,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=ud": { "model": "computercraft:block/monitor_normal_ud", "x": 270 }, - "facing=south,orientation=up,state=ud": { - "model": "computercraft:block/monitor_normal_ud", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "x": 270 }, - "facing=south,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 180, "x": 270 }, - "facing=west,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=rd": { "model": "computercraft:block/monitor_normal_rd", "x": 270 }, - "facing=south,orientation=up,state=rd": { - "model": "computercraft:block/monitor_normal_rd", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "x": 270 }, - "facing=south,orientation=up,state=lrd": { - "model": "computercraft:block/monitor_normal_lrd", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lrd": { - "model": "computercraft:block/monitor_normal_lrd", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lrd": { - "model": "computercraft:block/monitor_normal_lrd", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=ld": { "model": "computercraft:block/monitor_normal_ld", "x": 270 }, - "facing=south,orientation=up,state=ld": { - "model": "computercraft:block/monitor_normal_ld", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=rud": { "model": "computercraft:block/monitor_normal_rud", "x": 270 }, - "facing=south,orientation=up,state=rud": { - "model": "computercraft:block/monitor_normal_rud", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=rud": { - "model": "computercraft:block/monitor_normal_rud", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=rud": { - "model": "computercraft:block/monitor_normal_rud", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "x": 270 }, - "facing=south,orientation=up,state=lrud": { - "model": "computercraft:block/monitor_normal_lrud", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lrud": { - "model": "computercraft:block/monitor_normal_lrud", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lrud": { - "model": "computercraft:block/monitor_normal_lrud", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=lud": { "model": "computercraft:block/monitor_normal_lud", "x": 270 }, - "facing=south,orientation=up,state=lud": { - "model": "computercraft:block/monitor_normal_lud", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lud": { - "model": "computercraft:block/monitor_normal_lud", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lud": { - "model": "computercraft:block/monitor_normal_lud", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=ru": { "model": "computercraft:block/monitor_normal_ru", "x": 270 }, - "facing=south,orientation=up,state=ru": { - "model": "computercraft:block/monitor_normal_ru", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 90, "x": 270 }, - "facing=north,orientation=up,state=lru": { "model": "computercraft:block/monitor_normal_lru", "x": 270 }, - "facing=south,orientation=up,state=lru": { - "model": "computercraft:block/monitor_normal_lru", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lru": { - "model": "computercraft:block/monitor_normal_lru", "y": 270, "x": 270 - }, - "facing=east,orientation=up,state=lru": { - "model": "computercraft:block/monitor_normal_lru", "y": 90, "x": 270 - }, - "facing=north,orientation=up,state=lu": { "model": "computercraft:block/monitor_normal_lu", "x": 270 }, - "facing=south,orientation=up,state=lu": { - "model": "computercraft:block/monitor_normal_lu", "y": 180, "x": 270 - }, - "facing=west,orientation=up,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 270, "x": 270 }, - "facing=east,orientation=up,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 90, "x": 270 }, - - "facing=north,orientation=down,state=none": { "model": "computercraft:block/monitor_normal", "x": 90 }, - "facing=south,orientation=down,state=none": { - "model": "computercraft:block/monitor_normal", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=none": { "model": "computercraft:block/monitor_normal", "y": 270, "x": 90 }, - "facing=east,orientation=down,state=none": { "model": "computercraft:block/monitor_normal", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "x": 90 }, - "facing=south,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 180, "x": 90 }, - "facing=west,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 270, "x": 90 }, - "facing=east,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=lr": { "model": "computercraft:block/monitor_normal_lr", "x": 90 }, - "facing=south,orientation=down,state=lr": { - "model": "computercraft:block/monitor_normal_lr", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lr": { - "model": "computercraft:block/monitor_normal_lr", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "x": 90 }, - "facing=south,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 180, "x": 90 }, - "facing=west,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 270, "x": 90 }, - "facing=east,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "x": 90 }, - "facing=south,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 180, "x": 90 }, - "facing=west,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 270, "x": 90 }, - "facing=east,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=ud": { "model": "computercraft:block/monitor_normal_ud", "x": 90 }, - "facing=south,orientation=down,state=ud": { - "model": "computercraft:block/monitor_normal_ud", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=ud": { - "model": "computercraft:block/monitor_normal_ud", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "x": 90 }, - "facing=south,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 180, "x": 90 }, - "facing=west,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 270, "x": 90 }, - "facing=east,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=rd": { "model": "computercraft:block/monitor_normal_rd", "x": 90 }, - "facing=south,orientation=down,state=rd": { - "model": "computercraft:block/monitor_normal_rd", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=rd": { - "model": "computercraft:block/monitor_normal_rd", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "x": 90 }, - "facing=south,orientation=down,state=lrd": { - "model": "computercraft:block/monitor_normal_lrd", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lrd": { - "model": "computercraft:block/monitor_normal_lrd", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lrd": { - "model": "computercraft:block/monitor_normal_lrd", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=ld": { "model": "computercraft:block/monitor_normal_ld", "x": 90 }, - "facing=south,orientation=down,state=ld": { - "model": "computercraft:block/monitor_normal_ld", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=ld": { - "model": "computercraft:block/monitor_normal_ld", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=rud": { "model": "computercraft:block/monitor_normal_rud", "x": 90 }, - "facing=south,orientation=down,state=rud": { - "model": "computercraft:block/monitor_normal_rud", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=rud": { - "model": "computercraft:block/monitor_normal_rud", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=rud": { - "model": "computercraft:block/monitor_normal_rud", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "x": 90 }, - "facing=south,orientation=down,state=lrud": { - "model": "computercraft:block/monitor_normal_lrud", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lrud": { - "model": "computercraft:block/monitor_normal_lrud", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lrud": { - "model": "computercraft:block/monitor_normal_lrud", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=lud": { "model": "computercraft:block/monitor_normal_lud", "x": 90 }, - "facing=south,orientation=down,state=lud": { - "model": "computercraft:block/monitor_normal_lud", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lud": { - "model": "computercraft:block/monitor_normal_lud", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lud": { - "model": "computercraft:block/monitor_normal_lud", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=ru": { "model": "computercraft:block/monitor_normal_ru", "x": 90 }, - "facing=south,orientation=down,state=ru": { - "model": "computercraft:block/monitor_normal_ru", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=ru": { - "model": "computercraft:block/monitor_normal_ru", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 90, "x": 90 }, - "facing=north,orientation=down,state=lru": { "model": "computercraft:block/monitor_normal_lru", "x": 90 }, - "facing=south,orientation=down,state=lru": { - "model": "computercraft:block/monitor_normal_lru", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lru": { - "model": "computercraft:block/monitor_normal_lru", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lru": { - "model": "computercraft:block/monitor_normal_lru", "y": 90, "x": 90 - }, - "facing=north,orientation=down,state=lu": { "model": "computercraft:block/monitor_normal_lu", "x": 90 }, - "facing=south,orientation=down,state=lu": { - "model": "computercraft:block/monitor_normal_lu", "y": 180, "x": 90 - }, - "facing=west,orientation=down,state=lu": { - "model": "computercraft:block/monitor_normal_lu", "y": 270, "x": 90 - }, - "facing=east,orientation=down,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 90, "x": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/speaker.json b/src/main/resources/assets/computercraft/blockstates/speaker.json deleted file mode 100644 index 4b3935a54..000000000 --- a/src/main/resources/assets/computercraft/blockstates/speaker.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "variants": { - "facing=north": { "model": "computercraft:block/speaker" }, - "facing=south": { "model": "computercraft:block/speaker", "y": 180 }, - "facing=west": { "model": "computercraft:block/speaker", "y": 270 }, - "facing=east": { "model": "computercraft:block/speaker", "y": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/wired_modem_full.json b/src/main/resources/assets/computercraft/blockstates/wired_modem_full.json deleted file mode 100644 index ac068443f..000000000 --- a/src/main/resources/assets/computercraft/blockstates/wired_modem_full.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "variants": { - "modem=false,peripheral=false": { "model": "computercraft:block/wired_modem_full_off" }, - "modem=false,peripheral=true": { "model": "computercraft:block/wired_modem_full_off_peripheral" }, - "modem=true,peripheral=false": { "model": "computercraft:block/wired_modem_full_on" }, - "modem=true,peripheral=true": { "model": "computercraft:block/wired_modem_full_on_peripheral" } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/wireless_modem_advanced.json b/src/main/resources/assets/computercraft/blockstates/wireless_modem_advanced.json deleted file mode 100644 index 375ca9646..000000000 --- a/src/main/resources/assets/computercraft/blockstates/wireless_modem_advanced.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "variants": { - "facing=up,on=false": { "model": "computercraft:block/wireless_modem_advanced_off", "x": 270 }, - "facing=down,on=false": { "model": "computercraft:block/wireless_modem_advanced_off", "x": 90 }, - "facing=north,on=false": { "model": "computercraft:block/wireless_modem_advanced_off" }, - "facing=south,on=false": { "model": "computercraft:block/wireless_modem_advanced_off", "y": 180 }, - "facing=west,on=false": { "model": "computercraft:block/wireless_modem_advanced_off", "y": 270 }, - "facing=east,on=false": { "model": "computercraft:block/wireless_modem_advanced_off", "y": 90 }, - - "facing=up,on=true": { "model": "computercraft:block/wireless_modem_advanced_on", "x": 270 }, - "facing=down,on=true": { "model": "computercraft:block/wireless_modem_advanced_on", "x": 90 }, - "facing=north,on=true": { "model": "computercraft:block/wireless_modem_advanced_on" }, - "facing=south,on=true": { "model": "computercraft:block/wireless_modem_advanced_on", "y": 180 }, - "facing=west,on=true": { "model": "computercraft:block/wireless_modem_advanced_on", "y": 270 }, - "facing=east,on=true": { "model": "computercraft:block/wireless_modem_advanced_on", "y": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/wireless_modem_normal.json b/src/main/resources/assets/computercraft/blockstates/wireless_modem_normal.json deleted file mode 100644 index e39561423..000000000 --- a/src/main/resources/assets/computercraft/blockstates/wireless_modem_normal.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "variants": { - "facing=up,on=false": { "model": "computercraft:block/wireless_modem_normal_off", "x": 270 }, - "facing=down,on=false": { "model": "computercraft:block/wireless_modem_normal_off", "x": 90 }, - "facing=north,on=false": { "model": "computercraft:block/wireless_modem_normal_off" }, - "facing=south,on=false": { "model": "computercraft:block/wireless_modem_normal_off", "y": 180 }, - "facing=west,on=false": { "model": "computercraft:block/wireless_modem_normal_off", "y": 270 }, - "facing=east,on=false": { "model": "computercraft:block/wireless_modem_normal_off", "y": 90 }, - - "facing=up,on=true": { "model": "computercraft:block/wireless_modem_normal_on", "x": 270 }, - "facing=down,on=true": { "model": "computercraft:block/wireless_modem_normal_on", "x": 90 }, - "facing=north,on=true": { "model": "computercraft:block/wireless_modem_normal_on" }, - "facing=south,on=true": { "model": "computercraft:block/wireless_modem_normal_on", "y": 180 }, - "facing=west,on=true": { "model": "computercraft:block/wireless_modem_normal_on", "y": 270 }, - "facing=east,on=true": { "model": "computercraft:block/wireless_modem_normal_on", "y": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/lua/rom/motd.txt b/src/main/resources/assets/computercraft/lua/rom/motd.txt deleted file mode 100644 index 3b347b252..000000000 --- a/src/main/resources/assets/computercraft/lua/rom/motd.txt +++ /dev/null @@ -1,13 +0,0 @@ -View the source code at https://github.com/cc-tweaked/cc-restitched -View the documentation at https://wiki.computercraft.cc -Visit the forum at https://forums.computercraft.cc -You can disable these messages by running "set motd.enable false" -You can create directories with "mkdir". -Want to see hidden files? Run "set list.show_hidden true". -Run "list" or "ls" to see all files in a directory. -You can delete files and directories with "delete" or "rm". -Use "pastebin put" to upload a program to pastebin. -Use "pastebin get" to download a program from pastebin. -Use "pastebin run" to run a program from pastebin without saving it. -Use the "edit" program to create and edit your programs. -You can copy files with "copy" or "cp". diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua b/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua deleted file mode 100644 index 57ab7b916..000000000 --- a/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua +++ /dev/null @@ -1,24 +0,0 @@ -local date = os.date("*t") -if date.month == 1 and date.day == 1 then - print("Happy new year!") -elseif date.month == 12 and date.day == 24 then - print("Merry X-mas!") -elseif date.month == 10 and date.day == 31 then - print("OOoooOOOoooo! Spooky!") -else - local tMotd = {} - - for sPath in string.gmatch(settings.get("motd.path"), "[^:]+") do - if fs.exists(sPath) then - for sLine in io.lines(sPath) do - table.insert(tMotd, sLine) - end - end - end - - if #tMotd == 0 then - print("missingno") - else - print(tMotd[math.random(1, #tMotd)]) - end -end diff --git a/src/main/resources/assets/computercraft/models/block/computer_advanced_blinking.json b/src/main/resources/assets/computercraft/models/block/computer_advanced_blinking.json deleted file mode 100644 index ed4c9bec3..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_advanced_blinking.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_advanced_front_blink", - "side": "computercraft:block/computer_advanced_side", - "top": "computercraft:block/computer_advanced_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_advanced_off.json b/src/main/resources/assets/computercraft/models/block/computer_advanced_off.json deleted file mode 100644 index 8631c88ed..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_advanced_off.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_advanced_front", - "side": "computercraft:block/computer_advanced_side", - "top": "computercraft:block/computer_advanced_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_advanced_on.json b/src/main/resources/assets/computercraft/models/block/computer_advanced_on.json deleted file mode 100644 index 2692aab84..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_advanced_on.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_advanced_front_on", - "side": "computercraft:block/computer_advanced_side", - "top": "computercraft:block/computer_advanced_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_command_blinking.json b/src/main/resources/assets/computercraft/models/block/computer_command_blinking.json deleted file mode 100644 index 09d7ac1b3..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_command_blinking.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_command_front_blink", - "side": "computercraft:block/computer_command_side", - "top": "computercraft:block/computer_command_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_command_off.json b/src/main/resources/assets/computercraft/models/block/computer_command_off.json deleted file mode 100644 index eaa4970b9..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_command_off.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_command_front", - "side": "computercraft:block/computer_command_side", - "top": "computercraft:block/computer_command_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_command_on.json b/src/main/resources/assets/computercraft/models/block/computer_command_on.json deleted file mode 100644 index 7d4730140..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_command_on.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_command_front_on", - "side": "computercraft:block/computer_command_side", - "top": "computercraft:block/computer_command_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_normal_blinking.json b/src/main/resources/assets/computercraft/models/block/computer_normal_blinking.json deleted file mode 100644 index d6d70f696..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_normal_blinking.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_normal_front_blink", - "side": "computercraft:block/computer_normal_side", - "top": "computercraft:block/computer_normal_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_normal_off.json b/src/main/resources/assets/computercraft/models/block/computer_normal_off.json deleted file mode 100644 index 5d200f816..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_normal_off.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_normal_front", - "side": "computercraft:block/computer_normal_side", - "top": "computercraft:block/computer_normal_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_normal_on.json b/src/main/resources/assets/computercraft/models/block/computer_normal_on.json deleted file mode 100644 index f434d7fa8..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_normal_on.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_normal_front_on", - "side": "computercraft:block/computer_normal_side", - "top": "computercraft:block/computer_normal_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced.json deleted file mode 100644 index 3ff0ed5dc..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_16", - "side": "computercraft:block/monitor_advanced_4", - "top": "computercraft:block/monitor_advanced_0", - "back": "computercraft:block/monitor_advanced_4" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_d.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_d.json deleted file mode 100644 index d8936956d..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_d.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_20", - "side": "computercraft:block/monitor_advanced_36", - "top": "computercraft:block/monitor_advanced_0", - "back": "computercraft:block/monitor_advanced_36" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_item.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_item.json deleted file mode 100644 index 9420c1350..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_item.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/monitor_advanced_15", - "side": "computercraft:block/monitor_advanced_4", - "top": "computercraft:block/monitor_advanced_0" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_l.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_l.json deleted file mode 100644 index 3abee2204..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_l.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_19", - "side": "computercraft:block/monitor_advanced_4", - "top": "computercraft:block/monitor_advanced_1", - "back": "computercraft:block/monitor_advanced_33" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ld.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_ld.json deleted file mode 100644 index ee054dbc8..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ld.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_31", - "side": "computercraft:block/monitor_advanced_7", - "top": "computercraft:block/monitor_advanced_1", - "back": "computercraft:block/monitor_advanced_45" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lr.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lr.json deleted file mode 100644 index 320c8d354..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lr.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_18", - "side": "computercraft:block/monitor_advanced_4", - "top": "computercraft:block/monitor_advanced_2", - "back": "computercraft:block/monitor_advanced_34" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrd.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrd.json deleted file mode 100644 index 5f7a43407..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrd.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_30", - "side": "computercraft:block/monitor_advanced_7", - "top": "computercraft:block/monitor_advanced_2", - "back": "computercraft:block/monitor_advanced_46" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lru.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lru.json deleted file mode 100644 index 56acdd077..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lru.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_24", - "side": "computercraft:block/monitor_advanced_38", - "top": "computercraft:block/monitor_advanced_2", - "back": "computercraft:block/monitor_advanced_40" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrud.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrud.json deleted file mode 100644 index dce3c2baf..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrud.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_27", - "side": "computercraft:block/monitor_advanced_37", - "top": "computercraft:block/monitor_advanced_2", - "back": "computercraft:block/monitor_advanced_43" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lu.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lu.json deleted file mode 100644 index 905ebdce3..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lu.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_25", - "side": "computercraft:block/monitor_advanced_38", - "top": "computercraft:block/monitor_advanced_1", - "back": "computercraft:block/monitor_advanced_39" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lud.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lud.json deleted file mode 100644 index 43b110c03..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lud.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_28", - "side": "computercraft:block/monitor_advanced_37", - "top": "computercraft:block/monitor_advanced_1", - "back": "computercraft:block/monitor_advanced_42" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_r.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_r.json deleted file mode 100644 index 03d1d386f..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_r.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_17", - "side": "computercraft:block/monitor_advanced_4", - "top": "computercraft:block/monitor_advanced_3", - "back": "computercraft:block/monitor_advanced_35" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_rd.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_rd.json deleted file mode 100644 index 4ded80dba..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_rd.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_29", - "side": "computercraft:block/monitor_advanced_7", - "top": "computercraft:block/monitor_advanced_3", - "back": "computercraft:block/monitor_advanced_47" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ru.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_ru.json deleted file mode 100644 index 67cd36920..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ru.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_23", - "side": "computercraft:block/monitor_advanced_38", - "top": "computercraft:block/monitor_advanced_3", - "back": "computercraft:block/monitor_advanced_41" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_rud.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_rud.json deleted file mode 100644 index 0573ad049..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_rud.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_26", - "side": "computercraft:block/monitor_advanced_37", - "top": "computercraft:block/monitor_advanced_3", - "back": "computercraft:block/monitor_advanced_44" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_u.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_u.json deleted file mode 100644 index bdc9f7a2d..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_u.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_22", - "side": "computercraft:block/monitor_advanced_38", - "top": "computercraft:block/monitor_advanced_0", - "back": "computercraft:block/monitor_advanced_38" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ud.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_ud.json deleted file mode 100644 index 3987b109f..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ud.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_advanced_21", - "side": "computercraft:block/monitor_advanced_37", - "top": "computercraft:block/monitor_advanced_0", - "back": "computercraft:block/monitor_advanced_37" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal.json b/src/main/resources/assets/computercraft/models/block/monitor_normal.json deleted file mode 100644 index e7a669695..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_16", - "side": "computercraft:block/monitor_normal_4", - "top": "computercraft:block/monitor_normal_0", - "back": "computercraft:block/monitor_normal_4" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_d.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_d.json deleted file mode 100644 index ab3cf8bf4..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_d.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_20", - "side": "computercraft:block/monitor_normal_36", - "top": "computercraft:block/monitor_normal_0", - "back": "computercraft:block/monitor_normal_36" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_item.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_item.json deleted file mode 100644 index a8f01f314..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_item.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/monitor_normal_15", - "side": "computercraft:block/monitor_normal_4", - "top": "computercraft:block/monitor_normal_0" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_l.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_l.json deleted file mode 100644 index def167210..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_l.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_19", - "side": "computercraft:block/monitor_normal_4", - "top": "computercraft:block/monitor_normal_1", - "back": "computercraft:block/monitor_normal_33" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_ld.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_ld.json deleted file mode 100644 index 410d65029..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_ld.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_31", - "side": "computercraft:block/monitor_normal_7", - "top": "computercraft:block/monitor_normal_1", - "back": "computercraft:block/monitor_normal_45" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lr.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lr.json deleted file mode 100644 index 36243944d..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lr.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_18", - "side": "computercraft:block/monitor_normal_4", - "top": "computercraft:block/monitor_normal_2", - "back": "computercraft:block/monitor_normal_34" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lrd.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lrd.json deleted file mode 100644 index 1fe673561..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lrd.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_30", - "side": "computercraft:block/monitor_normal_7", - "top": "computercraft:block/monitor_normal_2", - "back": "computercraft:block/monitor_normal_46" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lru.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lru.json deleted file mode 100644 index d6c5b2ce4..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lru.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_24", - "side": "computercraft:block/monitor_normal_38", - "top": "computercraft:block/monitor_normal_2", - "back": "computercraft:block/monitor_normal_40" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lrud.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lrud.json deleted file mode 100644 index ba96ee76d..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lrud.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_27", - "side": "computercraft:block/monitor_normal_37", - "top": "computercraft:block/monitor_normal_2", - "back": "computercraft:block/monitor_normal_43" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lu.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lu.json deleted file mode 100644 index 444408d25..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lu.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_25", - "side": "computercraft:block/monitor_normal_38", - "top": "computercraft:block/monitor_normal_1", - "back": "computercraft:block/monitor_normal_39" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lud.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lud.json deleted file mode 100644 index 28f06d420..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lud.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_28", - "side": "computercraft:block/monitor_normal_37", - "top": "computercraft:block/monitor_normal_1", - "back": "computercraft:block/monitor_normal_42" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_r.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_r.json deleted file mode 100644 index 8b8eb4df1..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_r.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_17", - "side": "computercraft:block/monitor_normal_4", - "top": "computercraft:block/monitor_normal_3", - "back": "computercraft:block/monitor_normal_35" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_rd.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_rd.json deleted file mode 100644 index 61d7d1231..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_rd.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_29", - "side": "computercraft:block/monitor_normal_7", - "top": "computercraft:block/monitor_normal_3", - "back": "computercraft:block/monitor_normal_47" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_ru.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_ru.json deleted file mode 100644 index ddb474736..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_ru.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_23", - "side": "computercraft:block/monitor_normal_38", - "top": "computercraft:block/monitor_normal_3", - "back": "computercraft:block/monitor_normal_41" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_rud.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_rud.json deleted file mode 100644 index a8f272995..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_rud.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_26", - "side": "computercraft:block/monitor_normal_37", - "top": "computercraft:block/monitor_normal_3", - "back": "computercraft:block/monitor_normal_44" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_u.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_u.json deleted file mode 100644 index c7d67619b..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_u.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_22", - "side": "computercraft:block/monitor_normal_38", - "top": "computercraft:block/monitor_normal_0", - "back": "computercraft:block/monitor_normal_38" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_ud.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_ud.json deleted file mode 100644 index 0cbadcc4b..000000000 --- a/src/main/resources/assets/computercraft/models/block/monitor_normal_ud.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "computercraft:block/monitor_base", - "textures": { - "front": "computercraft:block/monitor_normal_21", - "side": "computercraft:block/monitor_normal_37", - "top": "computercraft:block/monitor_normal_0", - "back": "computercraft:block/monitor_normal_37" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/speaker.json b/src/main/resources/assets/computercraft/models/block/speaker.json deleted file mode 100644 index a2f45c10a..000000000 --- a/src/main/resources/assets/computercraft/models/block/speaker.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/speaker_front", - "side": "computercraft:block/speaker_side", - "top": "computercraft:block/speaker_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wired_modem_full_off.json b/src/main/resources/assets/computercraft/models/block/wired_modem_full_off.json deleted file mode 100644 index d6d2e5303..000000000 --- a/src/main/resources/assets/computercraft/models/block/wired_modem_full_off.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "block/cube_all", - "textures": { - "all": "computercraft:block/wired_modem_face" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wired_modem_full_off_peripheral.json b/src/main/resources/assets/computercraft/models/block/wired_modem_full_off_peripheral.json deleted file mode 100644 index 0c5c0e50c..000000000 --- a/src/main/resources/assets/computercraft/models/block/wired_modem_full_off_peripheral.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "block/cube_all", - "textures": { - "all": "computercraft:block/wired_modem_face_peripheral" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wired_modem_full_on.json b/src/main/resources/assets/computercraft/models/block/wired_modem_full_on.json deleted file mode 100644 index c36e45cff..000000000 --- a/src/main/resources/assets/computercraft/models/block/wired_modem_full_on.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "block/cube_all", - "textures": { - "all": "computercraft:block/wired_modem_face_on" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wired_modem_full_on_peripheral.json b/src/main/resources/assets/computercraft/models/block/wired_modem_full_on_peripheral.json deleted file mode 100644 index e4fb9858b..000000000 --- a/src/main/resources/assets/computercraft/models/block/wired_modem_full_on_peripheral.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "block/cube_all", - "textures": { - "all": "computercraft:block/wired_modem_face_peripheral_on" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wired_modem_off.json b/src/main/resources/assets/computercraft/models/block/wired_modem_off.json deleted file mode 100644 index 9c500700d..000000000 --- a/src/main/resources/assets/computercraft/models/block/wired_modem_off.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "computercraft:block/modem", - "textures": { - "front": "computercraft:block/wired_modem_face", - "back": "computercraft:block/modem_back" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wired_modem_off_peripheral.json b/src/main/resources/assets/computercraft/models/block/wired_modem_off_peripheral.json deleted file mode 100644 index 9532df960..000000000 --- a/src/main/resources/assets/computercraft/models/block/wired_modem_off_peripheral.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "computercraft:block/modem", - "textures": { - "front": "computercraft:block/wired_modem_face_peripheral", - "back": "computercraft:block/modem_back" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wired_modem_on.json b/src/main/resources/assets/computercraft/models/block/wired_modem_on.json deleted file mode 100644 index f69937299..000000000 --- a/src/main/resources/assets/computercraft/models/block/wired_modem_on.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "computercraft:block/modem", - "textures": { - "front": "computercraft:block/wired_modem_face_on", - "back": "computercraft:block/modem_back" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wired_modem_on_peripheral.json b/src/main/resources/assets/computercraft/models/block/wired_modem_on_peripheral.json deleted file mode 100644 index 22cccf90b..000000000 --- a/src/main/resources/assets/computercraft/models/block/wired_modem_on_peripheral.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "computercraft:block/modem", - "textures": { - "front": "computercraft:block/wired_modem_face_peripheral_on", - "back": "computercraft:block/modem_back" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wireless_modem_advanced_off.json b/src/main/resources/assets/computercraft/models/block/wireless_modem_advanced_off.json deleted file mode 100644 index a818ba19a..000000000 --- a/src/main/resources/assets/computercraft/models/block/wireless_modem_advanced_off.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "computercraft:block/modem", - "textures": { - "front": "computercraft:block/wireless_modem_advanced_face", - "back": "computercraft:block/modem_back" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wireless_modem_advanced_on.json b/src/main/resources/assets/computercraft/models/block/wireless_modem_advanced_on.json deleted file mode 100644 index 7327fa44a..000000000 --- a/src/main/resources/assets/computercraft/models/block/wireless_modem_advanced_on.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "computercraft:block/modem", - "textures": { - "front": "computercraft:block/wireless_modem_advanced_face_on", - "back": "computercraft:block/modem_back" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wireless_modem_normal_off.json b/src/main/resources/assets/computercraft/models/block/wireless_modem_normal_off.json deleted file mode 100644 index 2ac06bfd5..000000000 --- a/src/main/resources/assets/computercraft/models/block/wireless_modem_normal_off.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "computercraft:block/modem", - "textures": { - "front": "computercraft:block/wireless_modem_normal_face", - "back": "computercraft:block/modem_back" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/wireless_modem_normal_on.json b/src/main/resources/assets/computercraft/models/block/wireless_modem_normal_on.json deleted file mode 100644 index 0b0697741..000000000 --- a/src/main/resources/assets/computercraft/models/block/wireless_modem_normal_on.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "computercraft:block/modem", - "textures": { - "front": "computercraft:block/wireless_modem_normal_face_on", - "back": "computercraft:block/modem_back" - } -} diff --git a/src/main/resources/assets/computercraft/models/item/computer_advanced.json b/src/main/resources/assets/computercraft/models/item/computer_advanced.json deleted file mode 100644 index bbaf95089..000000000 --- a/src/main/resources/assets/computercraft/models/item/computer_advanced.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/computer_advanced_blinking" -} diff --git a/src/main/resources/assets/computercraft/models/item/computer_command.json b/src/main/resources/assets/computercraft/models/item/computer_command.json deleted file mode 100644 index c0df0ddd6..000000000 --- a/src/main/resources/assets/computercraft/models/item/computer_command.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/computer_command_blinking" -} diff --git a/src/main/resources/assets/computercraft/models/item/computer_normal.json b/src/main/resources/assets/computercraft/models/item/computer_normal.json deleted file mode 100644 index bf906f744..000000000 --- a/src/main/resources/assets/computercraft/models/item/computer_normal.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/computer_normal_blinking" -} diff --git a/src/main/resources/assets/computercraft/models/item/monitor_advanced.json b/src/main/resources/assets/computercraft/models/item/monitor_advanced.json deleted file mode 100644 index 52ff045f8..000000000 --- a/src/main/resources/assets/computercraft/models/item/monitor_advanced.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/monitor_advanced_item" -} diff --git a/src/main/resources/assets/computercraft/models/item/monitor_normal.json b/src/main/resources/assets/computercraft/models/item/monitor_normal.json deleted file mode 100644 index 29079e6b3..000000000 --- a/src/main/resources/assets/computercraft/models/item/monitor_normal.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/monitor_normal_item" -} diff --git a/src/main/resources/assets/computercraft/models/item/speaker.json b/src/main/resources/assets/computercraft/models/item/speaker.json deleted file mode 100644 index 3aed864e9..000000000 --- a/src/main/resources/assets/computercraft/models/item/speaker.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/speaker" -} diff --git a/src/main/resources/assets/computercraft/models/item/wired_modem.json b/src/main/resources/assets/computercraft/models/item/wired_modem.json deleted file mode 100644 index a1d809c37..000000000 --- a/src/main/resources/assets/computercraft/models/item/wired_modem.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/wired_modem_off" -} diff --git a/src/main/resources/assets/computercraft/models/item/wired_modem_full.json b/src/main/resources/assets/computercraft/models/item/wired_modem_full.json deleted file mode 100644 index 77237e07a..000000000 --- a/src/main/resources/assets/computercraft/models/item/wired_modem_full.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/wired_modem_full_off" -} diff --git a/src/main/resources/assets/computercraft/models/item/wireless_modem_advanced.json b/src/main/resources/assets/computercraft/models/item/wireless_modem_advanced.json deleted file mode 100644 index 801d0dd42..000000000 --- a/src/main/resources/assets/computercraft/models/item/wireless_modem_advanced.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/wireless_modem_advanced_off" -} diff --git a/src/main/resources/assets/computercraft/models/item/wireless_modem_normal.json b/src/main/resources/assets/computercraft/models/item/wireless_modem_normal.json deleted file mode 100644 index bf403a943..000000000 --- a/src/main/resources/assets/computercraft/models/item/wireless_modem_normal.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "computercraft:block/wireless_modem_normal_off" -} diff --git a/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.fsh b/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.fsh index f89635ca5..c1e089fed 100644 --- a/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.fsh +++ b/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.fsh @@ -1,17 +1,31 @@ #version 150 +#moj_import + #define FONT_WIDTH 6.0 #define FONT_HEIGHT 9.0 uniform sampler2D Sampler0; // Font -uniform int Width; -uniform int Height; uniform usamplerBuffer Tbo; -uniform vec3 Palette[16]; -in vec2 f_pos; +layout(std140) uniform MonitorData { + vec3 Palette[16]; + int Width; + int Height; + ivec2 CursorPos; + int CursorColour; +}; +uniform int CursorBlink; + +uniform vec4 ColorModulator; +uniform float FogStart; +uniform float FogEnd; +uniform vec4 FogColor; -out vec4 colour; +in float vertexDistance; +in vec2 fontPos; + +out vec4 fragColor; vec2 texture_corner(int index) { float x = 1.0 + float(index % 16) * (FONT_WIDTH + 2.0); @@ -19,8 +33,12 @@ vec2 texture_corner(int index) { return vec2(x, y); } +vec4 recolour(vec4 texture, int colour) { + return vec4(texture.rgb * Palette[colour], texture.rgba); +} + void main() { - vec2 term_pos = vec2(f_pos.x / FONT_WIDTH, f_pos.y / FONT_HEIGHT); + vec2 term_pos = vec2(fontPos.x / FONT_WIDTH, fontPos.y / FONT_HEIGHT); vec2 corner = floor(term_pos); ivec2 cell = ivec2(corner); @@ -35,6 +53,14 @@ void main() { int bg = int(texelFetch(Tbo, index + 2).r); vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT); - vec4 img = texture(Sampler0, (texture_corner(character) + pos) / 256.0); - colour = vec4(mix(Palette[bg], img.rgb * Palette[fg], img.a * mult), 1.0); + vec4 charTex = recolour(texture(Sampler0, (texture_corner(character) + pos) / 256.0), fg); + + // Applies the cursor on top of the current character if we're blinking and in the current cursor's cell. We do it + // this funky way to avoid branches. + vec4 cursorTex = recolour(texture(Sampler0, (texture_corner(95) + pos) / 256.0), CursorColour); // 95 = '_' + vec4 img = mix(charTex, cursorTex, cursorTex.a * float(CursorBlink) * (CursorPos == cell ? 1.0 : 0.0)); + + vec4 colour = vec4(mix(Palette[bg], img.rgb, img.a * mult), 1.0) * ColorModulator; + + fragColor = linear_fog(colour, vertexDistance, FogStart, FogEnd, FogColor); } diff --git a/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.json b/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.json index 9196160ee..fe2320b0e 100644 --- a/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.json +++ b/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.json @@ -6,8 +6,14 @@ "uniforms": [ { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, - { "name": "Width", "type": "int", "count": 1, "values": [ 1 ] }, - { "name": "Height", "type": "int", "count": 1, "values": [ 1 ] }, - { "name": "Tbo", "type": "int", "count": 1, "values": [ 3 ] } + { "name": "IViewRotMat", "type": "matrix3x3", "count": 9, "values": [ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }, + { "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] }, + { "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] }, + { "name": "FogShape", "type": "int", "count": 1, "values": [ 0 ] }, + + { "name": "Tbo", "type": "int", "count": 1, "values": [ 3 ] }, + { "name": "CursorBlink", "type": "int", "count": 1, "values": [ 0 ] } ] } diff --git a/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.vsh b/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.vsh index 8b673710b..885b20df5 100644 --- a/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.vsh +++ b/src/main/resources/assets/minecraft/shaders/core/monitor_tbo.vsh @@ -1,14 +1,21 @@ #version 150 +#moj_import + in vec3 Position; in vec2 UV0; uniform mat4 ModelViewMat; uniform mat4 ProjMat; +uniform mat3 IViewRotMat; +uniform int FogShape; -out vec2 f_pos; +out float vertexDistance; +out vec2 fontPos; void main() { gl_Position = ProjMat * ModelViewMat * vec4(Position, 1); - f_pos = UV0; + + vertexDistance = fog_distance(ModelViewMat, IViewRotMat * Position, FogShape); + fontPos = UV0; } diff --git a/src/main/resources/assets/minecraft/shaders/core/terminal.json b/src/main/resources/assets/minecraft/shaders/core/terminal.json deleted file mode 100644 index 2cd53c182..000000000 --- a/src/main/resources/assets/minecraft/shaders/core/terminal.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "vertex": "position_color_tex", - "fragment": "position_color_tex", - "attributes": [ "Position", "Color", "UV0" ], - "samplers": [ { "name": "Sampler0" } ], - "uniforms": [ - { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, - { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, - { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] } - ] -} diff --git a/src/main/resources/cc.accesswidener b/src/main/resources/cc.accesswidener index 5225f4bb7..148021c85 100644 --- a/src/main/resources/cc.accesswidener +++ b/src/main/resources/cc.accesswidener @@ -6,3 +6,11 @@ accessible method net/minecraft/client/renderer/RenderType create (Ljava/lang/St # SpeakerInstance/SpeakerManager accessible method com/mojang/blaze3d/audio/Channel pumpBuffers (I)V accessible field net/minecraft/client/sounds/SoundEngine executor Lnet/minecraft/client/sounds/SoundEngineExecutor; + +# DirectVertexBuffer +accessible field com/mojang/blaze3d/vertex/VertexBuffer vertextBufferId I +accessible field com/mojang/blaze3d/vertex/VertexBuffer indexType Lcom/mojang/blaze3d/vertex/VertexFormat$IndexType; +accessible field com/mojang/blaze3d/vertex/VertexBuffer indexCount I +accessible field com/mojang/blaze3d/vertex/VertexBuffer mode Lcom/mojang/blaze3d/vertex/VertexFormat$Mode; +accessible field com/mojang/blaze3d/vertex/VertexBuffer sequentialIndices Z +accessible field com/mojang/blaze3d/vertex/VertexBuffer format Lcom/mojang/blaze3d/vertex/VertexFormat; diff --git a/src/main/resources/data/c/tags/items/black_dyes.json b/src/main/resources/data/c/tags/items/black_dyes.json deleted file mode 100644 index 26b4e622b..000000000 --- a/src/main/resources/data/c/tags/items/black_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:black_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/blue_dyes.json b/src/main/resources/data/c/tags/items/blue_dyes.json deleted file mode 100644 index d22bad7b3..000000000 --- a/src/main/resources/data/c/tags/items/blue_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:blue_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/brown_dyes.json b/src/main/resources/data/c/tags/items/brown_dyes.json deleted file mode 100644 index eaa513928..000000000 --- a/src/main/resources/data/c/tags/items/brown_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:brown_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/cyan_dyes.json b/src/main/resources/data/c/tags/items/cyan_dyes.json deleted file mode 100644 index e9abb1523..000000000 --- a/src/main/resources/data/c/tags/items/cyan_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:cyan_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/ender_pearls.json b/src/main/resources/data/c/tags/items/ender_pearls.json deleted file mode 100644 index 98e6e7034..000000000 --- a/src/main/resources/data/c/tags/items/ender_pearls.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:ender_pearl" - ] -} diff --git a/src/main/resources/data/c/tags/items/glass_panes.json b/src/main/resources/data/c/tags/items/glass_panes.json deleted file mode 100644 index 0e953d099..000000000 --- a/src/main/resources/data/c/tags/items/glass_panes.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:green_stained_glass_pane", - "minecraft:light_blue_stained_glass_pane", - "minecraft:gray_stained_glass_pane", - "minecraft:red_stained_glass_pane", - "minecraft:lime_stained_glass_pane", - "minecraft:yellow_stained_glass_pane", - "minecraft:blue_stained_glass_pane", - "minecraft:pink_stained_glass_pane", - "minecraft:light_gray_stained_glass_pane", - "minecraft:orange_stained_glass_pane", - "minecraft:glass_pane", - "minecraft:purple_stained_glass_pane", - "minecraft:white_stained_glass_pane", - "minecraft:magenta_stained_glass_pane", - "minecraft:brown_stained_glass_pane", - "minecraft:black_stained_glass_pane", - "minecraft:cyan_stained_glass_pane" - ] -} diff --git a/src/main/resources/data/c/tags/items/gold_blocks.json b/src/main/resources/data/c/tags/items/gold_blocks.json deleted file mode 100644 index c67537a25..000000000 --- a/src/main/resources/data/c/tags/items/gold_blocks.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:gold_block" - ] -} diff --git a/src/main/resources/data/c/tags/items/gold_ingots.json b/src/main/resources/data/c/tags/items/gold_ingots.json deleted file mode 100644 index d95117008..000000000 --- a/src/main/resources/data/c/tags/items/gold_ingots.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:gold_ingot" - ] -} diff --git a/src/main/resources/data/c/tags/items/gray_dyes.json b/src/main/resources/data/c/tags/items/gray_dyes.json deleted file mode 100644 index 41ac3efcb..000000000 --- a/src/main/resources/data/c/tags/items/gray_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:gray_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/green_dyes.json b/src/main/resources/data/c/tags/items/green_dyes.json deleted file mode 100644 index 117da17a2..000000000 --- a/src/main/resources/data/c/tags/items/green_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:green_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/iron_ingots.json b/src/main/resources/data/c/tags/items/iron_ingots.json deleted file mode 100644 index 042626f2d..000000000 --- a/src/main/resources/data/c/tags/items/iron_ingots.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:iron_ingot" - ] -} diff --git a/src/main/resources/data/c/tags/items/light_blue_dyes.json b/src/main/resources/data/c/tags/items/light_blue_dyes.json deleted file mode 100644 index 5abfe433a..000000000 --- a/src/main/resources/data/c/tags/items/light_blue_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:light_blue_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/light_gray_dyes.json b/src/main/resources/data/c/tags/items/light_gray_dyes.json deleted file mode 100644 index 1efbe1882..000000000 --- a/src/main/resources/data/c/tags/items/light_gray_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:light_gray_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/lime_dyes.json b/src/main/resources/data/c/tags/items/lime_dyes.json deleted file mode 100644 index a5c6cadfd..000000000 --- a/src/main/resources/data/c/tags/items/lime_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:lime_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/magenta_dyes.json b/src/main/resources/data/c/tags/items/magenta_dyes.json deleted file mode 100644 index b53ca3614..000000000 --- a/src/main/resources/data/c/tags/items/magenta_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:magenta_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/orange_dyes.json b/src/main/resources/data/c/tags/items/orange_dyes.json deleted file mode 100644 index ce9bdea4a..000000000 --- a/src/main/resources/data/c/tags/items/orange_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:orange_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/pink_dyes.json b/src/main/resources/data/c/tags/items/pink_dyes.json deleted file mode 100644 index 62eab2038..000000000 --- a/src/main/resources/data/c/tags/items/pink_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:pink_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/purple_dyes.json b/src/main/resources/data/c/tags/items/purple_dyes.json deleted file mode 100644 index a0cc925d7..000000000 --- a/src/main/resources/data/c/tags/items/purple_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:purple_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/red_dyes.json b/src/main/resources/data/c/tags/items/red_dyes.json deleted file mode 100644 index c02a69287..000000000 --- a/src/main/resources/data/c/tags/items/red_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:red_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/redstone_dusts.json b/src/main/resources/data/c/tags/items/redstone_dusts.json deleted file mode 100644 index 7f9d96f1a..000000000 --- a/src/main/resources/data/c/tags/items/redstone_dusts.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:redstone" - ] -} diff --git a/src/main/resources/data/c/tags/items/stones.json b/src/main/resources/data/c/tags/items/stones.json deleted file mode 100644 index 28110bfa6..000000000 --- a/src/main/resources/data/c/tags/items/stones.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:andesite", - "minecraft:diorite", - "minecraft:granite", - "minecraft:infested_stone", - "minecraft:stone", - "minecraft:polished_andesite", - "minecraft:polished_diorite", - "minecraft:polished_granite" - ] -} diff --git a/src/main/resources/data/c/tags/items/white_dyes.json b/src/main/resources/data/c/tags/items/white_dyes.json deleted file mode 100644 index 59601ecf1..000000000 --- a/src/main/resources/data/c/tags/items/white_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:white_dye" - ] -} diff --git a/src/main/resources/data/c/tags/items/wooden_chests.json b/src/main/resources/data/c/tags/items/wooden_chests.json deleted file mode 100644 index 0777fa5ba..000000000 --- a/src/main/resources/data/c/tags/items/wooden_chests.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:trapped_chest", - "minecraft:chest" - ] -} diff --git a/src/main/resources/data/c/tags/items/yellow_dyes.json b/src/main/resources/data/c/tags/items/yellow_dyes.json deleted file mode 100644 index 4d4b0c28a..000000000 --- a/src/main/resources/data/c/tags/items/yellow_dyes.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:yellow_dye" - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/cable.json b/src/main/resources/data/computercraft/advancements/recipes/cable.json deleted file mode 100644 index e0aeae8ba..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/cable.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:cable" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_modem": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:cable" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:cable" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_modem", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/command_computer.json b/src/main/resources/data/computercraft/advancements/recipes/command_computer.json deleted file mode 100644 index 692278666..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/command_computer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:command_computer" ] - }, - "criteria": { - "has_redstone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:command_block" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:command_computer" } - } - }, - "requirements": [ - [ - "has_redstone", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computer_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computer_advanced.json deleted file mode 100644 index 96c0f57e4..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computer_advanced.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:advanced_computer" ] - }, - "criteria": { - "has_redstone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:redstone" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:advanced_computer" } - } - }, - "requirements": [ - [ - "has_redstone", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computer_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computer_normal.json deleted file mode 100644 index b8ef77055..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computer_normal.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:normal_computer" ] - }, - "criteria": { - "has_redstone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:redstone" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:normal_computer" } - } - }, - "requirements": [ - [ - "has_redstone", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/cable.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/cable.json deleted file mode 100644 index a702efff2..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/cable.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:cable" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_modem": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:cable" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_modem", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json deleted file mode 100644 index 53a82f857..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:computer_advanced" - ] - }, - "criteria": { - "has_components": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "minecraft:redstone" - }, - { - "item": "minecraft:gold_ingot" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:computer_advanced" - } - } - }, - "requirements": [ - [ - "has_components", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json deleted file mode 100644 index 88e5fa410..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:computer_command" - ] - }, - "criteria": { - "has_components": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "minecraft:command_block" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:computer_command" - } - } - }, - "requirements": [ - [ - "has_components", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json deleted file mode 100644 index 2f326d8a8..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:computer_normal" - ] - }, - "criteria": { - "has_redstone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "c:redstone_dusts" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:computer_normal" - } - } - }, - "requirements": [ - [ - "has_redstone", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json deleted file mode 100644 index e1956a298..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_1" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_1" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json deleted file mode 100644 index 6070f0464..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_10" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_10" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json deleted file mode 100644 index 60be444fd..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_11" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_11" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json deleted file mode 100644 index 911d4d202..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_12" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_12" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json deleted file mode 100644 index 7d6cb40a3..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_13" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_13" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json deleted file mode 100644 index 5d6f58e8a..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_14" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_14" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json deleted file mode 100644 index e2436725c..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_15" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_15" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json deleted file mode 100644 index b9dcb12e9..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_16" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_16" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json deleted file mode 100644 index 3b26dc5d0..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_2" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_2" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json deleted file mode 100644 index bbf5e3df1..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_3" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_3" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json deleted file mode 100644 index dc6a40b92..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_4" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_4" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json deleted file mode 100644 index 14e6e0284..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_5" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_5" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json deleted file mode 100644 index 302f48a6c..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_6" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_6" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json deleted file mode 100644 index c0f28ff83..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_7" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_7" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json deleted file mode 100644 index 75923e0e0..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_8" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_8" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json deleted file mode 100644 index 4a31c654f..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_9" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:disk_drive" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_9" - } - } - }, - "requirements": [ - [ - "has_drive", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json deleted file mode 100644 index 02d1205cb..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:disk_drive" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:disk_drive" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json deleted file mode 100644 index 57ceb3ec2..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:monitor_advanced" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:monitor_advanced" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json deleted file mode 100644 index 550e17388..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:monitor_normal" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:monitor_normal" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json deleted file mode 100644 index 91ee1d9cc..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/computercraft/speaker" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "computercraft:speaker" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/computercraft/speaker" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json deleted file mode 100644 index 51a2525d2..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/computercraft/wireless_modem_advanced" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "computercraft:wireless_modem_advanced" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/computercraft/wireless_modem_advanced" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json deleted file mode 100644 index a3653511d..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/computercraft/wireless_modem_normal" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "computercraft:wireless_modem_normal" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/computercraft/wireless_modem_normal" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json deleted file mode 100644 index 844dcf149..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/crafting_table" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:crafting_table" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/crafting_table" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json deleted file mode 100644 index cffab3444..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_axe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_axe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_axe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json deleted file mode 100644 index 8e3b66b89..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_hoe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_hoe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_hoe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json deleted file mode 100644 index 80c229d74..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_pickaxe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_pickaxe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_pickaxe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json deleted file mode 100644 index 51a0b82e3..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_shovel" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_shovel" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_shovel" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json deleted file mode 100644 index 5d1ff7615..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_sword" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_sword" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_sword" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json deleted file mode 100644 index cfd276eee..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_computer_advanced" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_apple": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "minecraft:golden_apple" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_computer_advanced" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_apple", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json deleted file mode 100644 index d52a8d59e..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_computer_normal" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_apple": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "minecraft:golden_apple" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_computer_normal" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_apple", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json deleted file mode 100644 index d4bd7a753..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/computercraft/speaker" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "computercraft:speaker" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/computercraft/speaker" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json deleted file mode 100644 index fcb68fc98..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/computercraft/wireless_modem_advanced" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "computercraft:wireless_modem_advanced" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/computercraft/wireless_modem_advanced" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json deleted file mode 100644 index d8f8c39e5..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/computercraft/wireless_modem_normal" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "computercraft:wireless_modem_normal" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/computercraft/wireless_modem_normal" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json deleted file mode 100644 index 7c28e4abf..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/crafting_table" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:crafting_table" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/crafting_table" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json deleted file mode 100644 index 0db58f942..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_axe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_axe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_axe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json deleted file mode 100644 index 8853ce7a8..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_hoe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_hoe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_hoe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json deleted file mode 100644 index 32b10b215..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_pickaxe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_pickaxe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_pickaxe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json deleted file mode 100644 index 36ec5a262..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_shovel" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_shovel" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_shovel" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json deleted file mode 100644 index 951089086..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_sword" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_sword" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_sword" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/printer.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/printer.json deleted file mode 100644 index cf068812a..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/printer.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:printer" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:printer" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/speaker.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/speaker.json deleted file mode 100644 index 4f786e601..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/speaker.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:speaker" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:speaker" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json deleted file mode 100644 index dd742e376..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_advanced/computercraft/speaker" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_advanced" - }, - { - "item": "computercraft:speaker" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_advanced/computercraft/speaker" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json deleted file mode 100644 index 008476105..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_advanced/computercraft/wireless_modem_advanced" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_advanced" - }, - { - "item": "computercraft:wireless_modem_advanced" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_advanced/computercraft/wireless_modem_advanced" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json deleted file mode 100644 index 05716273b..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_advanced/computercraft/wireless_modem_normal" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_advanced" - }, - { - "item": "computercraft:wireless_modem_normal" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_advanced/computercraft/wireless_modem_normal" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json deleted file mode 100644 index 67e80634f..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_advanced/minecraft/crafting_table" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_advanced" - }, - { - "item": "minecraft:crafting_table" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_advanced/minecraft/crafting_table" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json deleted file mode 100644 index cd6cb053c..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_advanced/minecraft/diamond_axe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_advanced" - }, - { - "item": "minecraft:diamond_axe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_advanced/minecraft/diamond_axe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json deleted file mode 100644 index ff2b00194..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_advanced/minecraft/diamond_hoe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_advanced" - }, - { - "item": "minecraft:diamond_hoe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_advanced/minecraft/diamond_hoe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json deleted file mode 100644 index af0143b03..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_advanced/minecraft/diamond_pickaxe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_advanced" - }, - { - "item": "minecraft:diamond_pickaxe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_advanced/minecraft/diamond_pickaxe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json deleted file mode 100644 index 8400b43ce..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_advanced/minecraft/diamond_shovel" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_advanced" - }, - { - "item": "minecraft:diamond_shovel" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_advanced/minecraft/diamond_shovel" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json deleted file mode 100644 index d48e41149..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_advanced/minecraft/diamond_sword" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_advanced" - }, - { - "item": "minecraft:diamond_sword" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_advanced/minecraft/diamond_sword" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json deleted file mode 100644 index d73caac29..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_normal/computercraft/speaker" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_normal" - }, - { - "item": "computercraft:speaker" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_normal/computercraft/speaker" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json deleted file mode 100644 index 5570d1113..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_normal/computercraft/wireless_modem_advanced" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_normal" - }, - { - "item": "computercraft:wireless_modem_advanced" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_normal/computercraft/wireless_modem_advanced" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json deleted file mode 100644 index 1f5eac5ad..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_normal/computercraft/wireless_modem_normal" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_normal" - }, - { - "item": "computercraft:wireless_modem_normal" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_normal/computercraft/wireless_modem_normal" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json deleted file mode 100644 index 2b6a255de..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_normal/minecraft/crafting_table" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_normal" - }, - { - "item": "minecraft:crafting_table" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_normal/minecraft/crafting_table" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json deleted file mode 100644 index 1b9997448..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_normal/minecraft/diamond_axe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_normal" - }, - { - "item": "minecraft:diamond_axe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_normal/minecraft/diamond_axe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json deleted file mode 100644 index 3435cc116..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_normal/minecraft/diamond_hoe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_normal" - }, - { - "item": "minecraft:diamond_hoe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_normal/minecraft/diamond_hoe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json deleted file mode 100644 index d86ee5e65..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_normal/minecraft/diamond_pickaxe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_normal" - }, - { - "item": "minecraft:diamond_pickaxe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_normal/minecraft/diamond_pickaxe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json deleted file mode 100644 index 447f249d2..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_normal/minecraft/diamond_shovel" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_normal" - }, - { - "item": "minecraft:diamond_shovel" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_normal/minecraft/diamond_shovel" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json deleted file mode 100644 index 5a6457a28..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:turtle_normal/minecraft/diamond_sword" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:turtle_normal" - }, - { - "item": "minecraft:diamond_sword" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:turtle_normal/minecraft/diamond_sword" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json deleted file mode 100644 index bd1237c8d..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:wired_modem" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_cable": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:cable" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:wired_modem" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_cable", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json deleted file mode 100644 index 7ebb299b0..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:wired_modem_full_from" - ] - }, - "criteria": { - "has_modem": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:wired_modem" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:wired_modem_full_from" - } - } - }, - "requirements": [ - [ - "has_modem", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json deleted file mode 100644 index 40eafc1cb..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:wired_modem_full_to" - ] - }, - "criteria": { - "has_modem": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:wired_modem" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:wired_modem_full_to" - } - } - }, - "requirements": [ - [ - "has_modem", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json deleted file mode 100644 index bdad47dd0..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:wireless_modem_advanced" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_wireless": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:wireless_modem_normal" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:wireless_modem_advanced" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_wireless", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json deleted file mode 100644 index c0bc76f9d..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:wireless_modem_normal" - ] - }, - "criteria": { - "has_computer": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "computercraft:computer" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:wireless_modem_normal" - } - } - }, - "requirements": [ - [ - "has_computer", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/disk_drive.json b/src/main/resources/data/computercraft/advancements/recipes/disk_drive.json deleted file mode 100644 index b1225ca70..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/disk_drive.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:disk_drive" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:disk_drive" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/disk.json b/src/main/resources/data/computercraft/advancements/recipes/generated/disk.json deleted file mode 100644 index 94c07e6d9..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/disk.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:generated/disk/disk_1", - "computercraft:generated/disk/disk_2", - "computercraft:generated/disk/disk_3", - "computercraft:generated/disk/disk_4", - "computercraft:generated/disk/disk_5", - "computercraft:generated/disk/disk_6", - "computercraft:generated/disk/disk_7", - "computercraft:generated/disk/disk_8", - "computercraft:generated/disk/disk_9", - "computercraft:generated/disk/disk_10", - "computercraft:generated/disk/disk_11", - "computercraft:generated/disk/disk_12", - "computercraft:generated/disk/disk_13", - "computercraft:generated/disk/disk_14", - "computercraft:generated/disk/disk_15", - "computercraft:generated/disk/disk_16" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:disk_drive" } ] - } - }, - "has_recipe_1": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_1" } - }, - "has_recipe_2": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_2" } - }, - "has_recipe_3": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_3" } - }, - "has_recipe_4": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_4" } - }, - "has_recipe_5": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_5" } - }, - "has_recipe_6": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_6" } - }, - "has_recipe_7": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_7" } - }, - "has_recipe_8": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_8" } - }, - "has_recipe_9": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_9" } - }, - "has_recipe_10": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_10" } - }, - "has_recipe_11": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_11" } - }, - "has_recipe_12": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_12" } - }, - "has_recipe_13": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_13" } - }, - "has_recipe_14": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_14" } - }, - "has_recipe_15": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_15" } - }, - "has_recipe_16": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_16" } - } - }, - "requirements": [ - [ - "has_drive", - "has_recipe_1", - "has_recipe_2", - "has_recipe_3", - "has_recipe_4", - "has_recipe_5", - "has_recipe_6", - "has_recipe_7", - "has_recipe_8", - "has_recipe_9", - "has_recipe_10", - "has_recipe_11", - "has_recipe_12", - "has_recipe_13", - "has_recipe_14", - "has_recipe_15", - "has_recipe_16" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_speaker.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_speaker.json deleted file mode 100644 index 3b9da6c6f..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_speaker.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_advanced/computercraft_speaker" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_advanced" }, - { "item": "computercraft:speaker" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_advanced/computercraft_speaker" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json deleted file mode 100644 index ce426a0f9..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_advanced/computercraft_wireless_modem_advanced" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_advanced" }, - { "item": "computercraft:wireless_modem_advanced" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_advanced/computercraft_wireless_modem_advanced" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json deleted file mode 100644 index d92bae7b0..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_advanced/computercraft_wireless_modem_normal" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_advanced" }, - { "item": "computercraft:wireless_modem_normal" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_advanced/computercraft_wireless_modem_normal" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_speaker.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_speaker.json deleted file mode 100644 index a0fac97f9..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_speaker.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_normal/computercraft_speaker" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_normal" }, - { "item": "computercraft:speaker" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_normal/computercraft_speaker" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 29c8cb86b..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_normal/computercraft_wireless_modem_advanced" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_normal" }, - { "item": "computercraft:wireless_modem_advanced" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_normal/computercraft_wireless_modem_advanced" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json deleted file mode 100644 index 19fe726ee..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_normal/computercraft_wireless_modem_normal" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_normal" }, - { "item": "computercraft:wireless_modem_normal" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_normal/computercraft_wireless_modem_normal" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_speaker.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_speaker.json deleted file mode 100644 index 09942d3d5..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_speaker.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/computercraft_speaker" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "computercraft:speaker" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/computercraft_speaker" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 23ed3111c..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/computercraft_wireless_modem_advanced" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "computercraft:wireless_modem_advanced" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/computercraft_wireless_modem_advanced" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json deleted file mode 100644 index e2613b21f..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/computercraft_wireless_modem_normal" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "computercraft:wireless_modem_normal" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/computercraft_wireless_modem_normal" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_crafting_table.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_crafting_table.json deleted file mode 100644 index c6c86d47a..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_crafting_table.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_crafting_table" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:crafting_table" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_crafting_table" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_axe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_axe.json deleted file mode 100644 index 6c1adcd84..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_axe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_axe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_axe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_axe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json deleted file mode 100644 index d906a8317..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_hoe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_hoe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_hoe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json deleted file mode 100644 index 9d59c615e..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_pickaxe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_pickaxe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_pickaxe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json deleted file mode 100644 index efc7a3fce..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_shovel" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_shovel" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_shovel" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_sword.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_sword.json deleted file mode 100644 index ad9f19c17..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_sword.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_sword" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_sword" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_sword" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_speaker.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_speaker.json deleted file mode 100644 index 6d18d9ee2..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_speaker.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/computercraft_speaker" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "computercraft:speaker" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/computercraft_speaker" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 5fe595acc..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/computercraft_wireless_modem_advanced" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "computercraft:wireless_modem_advanced" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/computercraft_wireless_modem_advanced" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json deleted file mode 100644 index 8d43a7c65..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/computercraft_wireless_modem_normal" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "computercraft:wireless_modem_normal" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/computercraft_wireless_modem_normal" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_crafting_table.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_crafting_table.json deleted file mode 100644 index 2bee28454..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_crafting_table.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_crafting_table" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:crafting_table" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_crafting_table" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_axe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_axe.json deleted file mode 100644 index df0b816a6..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_axe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_axe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_axe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_axe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_hoe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_hoe.json deleted file mode 100644 index 8df26b012..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_hoe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_hoe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_hoe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_hoe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json deleted file mode 100644 index e83d19e7b..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_pickaxe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_pickaxe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_pickaxe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_shovel.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_shovel.json deleted file mode 100644 index abeddd89b..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_shovel.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_shovel" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_shovel" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_shovel" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_sword.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_sword.json deleted file mode 100644 index 8930c40dd..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_sword.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_sword" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_sword" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_sword" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/monitor_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/monitor_advanced.json deleted file mode 100644 index 270f01765..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/monitor_advanced.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:monitor_advanced" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:monitor_advanced" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/monitor_normal.json b/src/main/resources/data/computercraft/advancements/recipes/monitor_normal.json deleted file mode 100644 index b1076ddf0..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/monitor_normal.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:normal_monitor" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:normal_monitor" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_advanced.json deleted file mode 100644 index b74f2d529..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_advanced.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:pocket_computer_advanced" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_apple": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:golden_apple" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:pocket_computer_advanced" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_apple", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_normal.json b/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_normal.json deleted file mode 100644 index 02f6be078..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_normal.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:normal_pocket_computer_normal" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_apple": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:golden_apple" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:pocket_computer_normal" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_apple", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/printed_book.json b/src/main/resources/data/computercraft/advancements/recipes/printed_book.json deleted file mode 100644 index 1d6bd81ac..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/printed_book.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:printed_book" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:printed_page" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:printed_book" } - } - }, - "requirements": [ - [ - "has_normal", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/printed_pages.json b/src/main/resources/data/computercraft/advancements/recipes/printed_pages.json deleted file mode 100644 index b87a31a50..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/printed_pages.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:printed_pages" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:printer" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:printed_pages" } - } - }, - "requirements": [ - [ - "has_normal", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/printer.json b/src/main/resources/data/computercraft/advancements/recipes/printer.json deleted file mode 100644 index 9e00f37a7..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/printer.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:printer" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:printer" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/printout.json b/src/main/resources/data/computercraft/advancements/recipes/printout.json deleted file mode 100644 index ef0e9f314..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/printout.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:printout" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:printer" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:printout" } - } - }, - "requirements": [ - [ - "has_normal", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/skull_cloudy.json b/src/main/resources/data/computercraft/advancements/recipes/skull_cloudy.json deleted file mode 100644 index 6ab01fe65..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/skull_cloudy.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:skull_cloudy" ] - }, - "criteria": { - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:skull_cloudy" } - } - }, - "requirements": [ - [ - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/skull_dan200.json b/src/main/resources/data/computercraft/advancements/recipes/skull_dan200.json deleted file mode 100644 index 277c0b477..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/skull_dan200.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:skull_dan200" ] - }, - "criteria": { - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:skull_dan200" } - } - }, - "requirements": [ - [ - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/speaker.json b/src/main/resources/data/computercraft/advancements/recipes/speaker.json deleted file mode 100644 index 721c93595..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/speaker.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:speaker" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_noteblock": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:note_block" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:speaker" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_noteblock", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/turtle_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/turtle_advanced.json deleted file mode 100644 index 77dc9d4e8..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/turtle_advanced.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:turtle_advanced" ] - }, - "criteria": { - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:turtle_advanced" } - } - }, - "requirements": [ - [ - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/turtle_normal.json b/src/main/resources/data/computercraft/advancements/recipes/turtle_normal.json deleted file mode 100644 index 482be3e1c..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/turtle_normal.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:normal_turtle_normal" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:turtle_normal" } - } - }, - "requirements": [ - [ - "has_normal", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/wired_modem.json b/src/main/resources/data/computercraft/advancements/recipes/wired_modem.json deleted file mode 100644 index ec4cef5a9..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/wired_modem.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:wired_modem", - "computercraft:wired_modem_full_to", - "computercraft:wired_modem_full_from" - ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_cable": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:wired_modem" } ] - } - }, - "has_modem_full": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:wired_modem_full" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:wired_modem" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_cable", - "has_modem_full", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_advanced.json deleted file mode 100644 index 8819a76f5..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_advanced.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:wireless_modem_advanced" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_wireless": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:wireless_modem_normal" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:wireless_modem_advanced" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_wireless", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_normal.json deleted file mode 100644 index f82624da3..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_normal.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:wireless_modem_normal" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:wireless_modem_normal" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/cable.json b/src/main/resources/data/computercraft/loot_tables/blocks/cable.json deleted file mode 100644 index 0bc4cd077..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/cable.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "cable", - "rolls": 1, - "entries": [ - { "type": "minecraft:item", "name": "computercraft:cable" } - ], - "conditions": [ - { "condition": "minecraft:survives_explosion" }, - { - "condition": "minecraft:block_state_property", - "block": "computercraft:cable", - "properties": { "cable": "true" } - } - ] - }, - { - "name": "wired_modem", - "rolls": 1, - "entries": [ - { "type": "minecraft:item", "name": "computercraft:wired_modem" } - ], - "conditions": [ - { "condition": "minecraft:survives_explosion" }, - { - "condition": "minecraft:inverted", - "term": { - "condition": "minecraft:block_state_property", - "block": "computercraft:cable", - "properties": { "modem": "none" } - } - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json deleted file mode 100644 index f5174622f..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:dynamic", - "name": "computercraft:computer" - } - ], - "conditions": [ - { - "condition": "minecraft:alternative", - "terms": [ - { - "condition": "computercraft:block_named" - }, - { - "condition": "computercraft:has_id" - }, - { - "condition": "minecraft:inverted", - "term": { - "condition": "computercraft:player_creative" - } - } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json deleted file mode 100644 index f5174622f..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:dynamic", - "name": "computercraft:computer" - } - ], - "conditions": [ - { - "condition": "minecraft:alternative", - "terms": [ - { - "condition": "computercraft:block_named" - }, - { - "condition": "computercraft:has_id" - }, - { - "condition": "minecraft:inverted", - "term": { - "condition": "computercraft:player_creative" - } - } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json deleted file mode 100644 index f5174622f..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:dynamic", - "name": "computercraft:computer" - } - ], - "conditions": [ - { - "condition": "minecraft:alternative", - "terms": [ - { - "condition": "computercraft:block_named" - }, - { - "condition": "computercraft:has_id" - }, - { - "condition": "minecraft:inverted", - "term": { - "condition": "computercraft:player_creative" - } - } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json b/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json deleted file mode 100644 index 26dd811af..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:item", - "name": "computercraft:disk_drive" - } - ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json deleted file mode 100644 index 9b9653008..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:item", - "name": "computercraft:monitor_advanced" - } - ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json deleted file mode 100644 index 1181c96e9..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:item", - "name": "computercraft:monitor_normal" - } - ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json b/src/main/resources/data/computercraft/loot_tables/blocks/printer.json deleted file mode 100644 index af72c6461..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:item", - "name": "computercraft:printer" - } - ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json b/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json deleted file mode 100644 index 3549a6a79..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:item", - "name": "computercraft:speaker" - } - ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json deleted file mode 100644 index f5174622f..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:dynamic", - "name": "computercraft:computer" - } - ], - "conditions": [ - { - "condition": "minecraft:alternative", - "terms": [ - { - "condition": "computercraft:block_named" - }, - { - "condition": "computercraft:has_id" - }, - { - "condition": "minecraft:inverted", - "term": { - "condition": "computercraft:player_creative" - } - } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json deleted file mode 100644 index f5174622f..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:dynamic", - "name": "computercraft:computer" - } - ], - "conditions": [ - { - "condition": "minecraft:alternative", - "terms": [ - { - "condition": "computercraft:block_named" - }, - { - "condition": "computercraft:has_id" - }, - { - "condition": "minecraft:inverted", - "term": { - "condition": "computercraft:player_creative" - } - } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json b/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json deleted file mode 100644 index f167008af..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:item", - "name": "computercraft:wired_modem_full" - } - ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json deleted file mode 100644 index 56c77b36f..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:item", - "name": "computercraft:wireless_modem_advanced" - } - ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json deleted file mode 100644 index b4a0a9914..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { - "type": "minecraft:item", - "name": "computercraft:wireless_modem_normal" - } - ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.md b/src/main/resources/data/computercraft/lua/rom/help/changelog.md index 8f58dd7b3..99d652883 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.md +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.md @@ -1,3 +1,24 @@ +# New features in CC: Tweaked 1.100.5 (CC: Restitched 1.100.4) + +* Improve performance of monitor rendering. + +Several bug fixes: +* Various documentation fixes (bclindner, Hasaabitt) +* Speaker sounds are now correctly positioned on the centre of the speaker block. + +# New features in CC: Tweaked 1.100.4 + +Several bug fixes: +* Fix the monitor watching blocking the main thread when chunks are slow to load. + +# New features in CC: Tweaked 1.100.3 + +Several bug fixes: +* Fix client disconnect when uploading large files. +* Correctly handling empty computer ID file. +* Fix the normal turtle recipe not being unlocked. +* Remove turtle fake EntityType. + # New features in CC: Tweaked 1.100.2 Several bug fixes: diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md index bbd0e76f2..592eb933f 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md @@ -1,7 +1,9 @@ -New features in CC: Tweaked 1.100.2 +New features in CC: Tweaked 1.100.5 (CC: Restitched 1.100.4) + +* Improve performance of monitor rendering. Several bug fixes: -* Fix wired modems swapping the modem/peripheral block state. -* Remove debugging logging line from `turtle.attack`. +* Various documentation fixes (bclindner, Hasaabitt) +* Speaker sounds are now correctly positioned on the centre of the speaker block. Type "help changelog" to see the full version history. diff --git a/src/main/resources/data/computercraft/lua/rom/programs/shell.lua b/src/main/resources/data/computercraft/lua/rom/programs/shell.lua index f24c0c4fc..f2649f47a 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/shell.lua @@ -3,7 +3,7 @@ -- It allows you to @{run|start programs}, @{setCompletionFunction|add -- completion for a program}, and much more. -- --- @{shell} is not a "true" API. Instead, it is a standard program, which its +-- @{shell} is not a "true" API. Instead, it is a standard program, which injects its -- API into the programs that it launches. This allows for multiple shells to -- run at the same time, but means that the API is not available in the global -- environment, and so is unavailable to other @{os.loadAPI|APIs}. diff --git a/src/main/resources/data/computercraft/recipes/cable.json b/src/main/resources/data/computercraft/recipes/cable.json deleted file mode 100644 index 2d0f86d73..000000000 --- a/src/main/resources/data/computercraft/recipes/cable.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - " # ", - "#R#", - " # " - ], - "key": { - "#": { - "tag": "c:stones" - }, - "R": { - "tag": "c:redstone_dusts" - } - }, - "result": { - "item": "computercraft:cable", - "count": 6 - } -} diff --git a/src/main/resources/data/computercraft/recipes/colour.json b/src/main/resources/data/computercraft/recipes/colour.json deleted file mode 100644 index ff190e755..000000000 --- a/src/main/resources/data/computercraft/recipes/colour.json +++ /dev/null @@ -1 +0,0 @@ -{ "type": "computercraft:colour" } diff --git a/src/main/resources/data/computercraft/recipes/computer_advanced.json b/src/main/resources/data/computercraft/recipes/computer_advanced.json deleted file mode 100644 index 02208c079..000000000 --- a/src/main/resources/data/computercraft/recipes/computer_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#R#", - "#G#" - ], - "key": { - "#": { - "tag": "c:gold_ingots" - }, - "R": { - "tag": "c:redstone_dusts" - }, - "G": { - "tag": "c:glass_panes" - } - }, - "result": { - "item": "computercraft:computer_advanced" - } -} diff --git a/src/main/resources/data/computercraft/recipes/computer_command.json b/src/main/resources/data/computercraft/recipes/computer_command.json deleted file mode 100644 index 61b1b3b14..000000000 --- a/src/main/resources/data/computercraft/recipes/computer_command.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#R#", - "#G#" - ], - "key": { - "#": { - "tag": "c:gold_ingots" - }, - "R": { - "item": "minecraft:command_block" - }, - "G": { - "tag": "c:glass_panes" - } - }, - "result": { - "item": "computercraft:computer_command" - } -} diff --git a/src/main/resources/data/computercraft/recipes/computer_normal.json b/src/main/resources/data/computercraft/recipes/computer_normal.json deleted file mode 100644 index 3271c2551..000000000 --- a/src/main/resources/data/computercraft/recipes/computer_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#R#", - "#G#" - ], - "key": { - "#": { - "tag": "c:stones" - }, - "R": { - "tag": "c:redstone_dusts" - }, - "G": { - "tag": "c:glass_panes" - } - }, - "result": { - "item": "computercraft:computer_normal" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk.json b/src/main/resources/data/computercraft/recipes/disk.json deleted file mode 100644 index 5dfba2271..000000000 --- a/src/main/resources/data/computercraft/recipes/disk.json +++ /dev/null @@ -1 +0,0 @@ -{ "type": "computercraft:disk" } diff --git a/src/main/resources/data/computercraft/recipes/disk_1.json b/src/main/resources/data/computercraft/recipes/disk_1.json deleted file mode 100644 index f58c4524d..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_1.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:black_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:1118481}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_10.json b/src/main/resources/data/computercraft/recipes/disk_10.json deleted file mode 100644 index be3c706d6..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_10.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:pink_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:15905484}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_11.json b/src/main/resources/data/computercraft/recipes/disk_11.json deleted file mode 100644 index b16467e7a..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_11.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:lime_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:8375321}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_12.json b/src/main/resources/data/computercraft/recipes/disk_12.json deleted file mode 100644 index c0ff791a8..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_12.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:yellow_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:14605932}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_13.json b/src/main/resources/data/computercraft/recipes/disk_13.json deleted file mode 100644 index 8cf914c0c..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_13.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:light_blue_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:10072818}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_14.json b/src/main/resources/data/computercraft/recipes/disk_14.json deleted file mode 100644 index a63ed9a0c..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_14.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:magenta_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:15040472}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_15.json b/src/main/resources/data/computercraft/recipes/disk_15.json deleted file mode 100644 index 96e20a117..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_15.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:orange_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:15905331}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_16.json b/src/main/resources/data/computercraft/recipes/disk_16.json deleted file mode 100644 index b3e31354f..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_16.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:white_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:15790320}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_2.json b/src/main/resources/data/computercraft/recipes/disk_2.json deleted file mode 100644 index b211373ca..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_2.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:red_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:13388876}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_3.json b/src/main/resources/data/computercraft/recipes/disk_3.json deleted file mode 100644 index 311e7fc28..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_3.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:green_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:5744206}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_4.json b/src/main/resources/data/computercraft/recipes/disk_4.json deleted file mode 100644 index dad728d09..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_4.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:brown_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:8349260}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_5.json b/src/main/resources/data/computercraft/recipes/disk_5.json deleted file mode 100644 index 52eca6cf8..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_5.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:blue_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:3368652}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_6.json b/src/main/resources/data/computercraft/recipes/disk_6.json deleted file mode 100644 index f21b7d509..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_6.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:purple_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:11691749}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_7.json b/src/main/resources/data/computercraft/recipes/disk_7.json deleted file mode 100644 index 6c5d9335f..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_7.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:cyan_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:5020082}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_8.json b/src/main/resources/data/computercraft/recipes/disk_8.json deleted file mode 100644 index 5670d5fdb..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_8.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:light_gray_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:10066329}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_9.json b/src/main/resources/data/computercraft/recipes/disk_9.json deleted file mode 100644 index b1b28a606..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_9.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { - "tag": "c:redstone_dusts" - }, - { - "item": "minecraft:paper" - }, - { - "item": "minecraft:gray_dye" - } - ], - "result": { - "item": "computercraft:disk", - "nbt": "{Color:5000268}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_drive.json b/src/main/resources/data/computercraft/recipes/disk_drive.json deleted file mode 100644 index af158529d..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_drive.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#R#", - "#R#" - ], - "key": { - "#": { - "tag": "c:stones" - }, - "R": { - "tag": "c:redstone_dusts" - } - }, - "result": { - "item": "computercraft:disk_drive" - } -} diff --git a/src/main/resources/data/computercraft/recipes/monitor_advanced.json b/src/main/resources/data/computercraft/recipes/monitor_advanced.json deleted file mode 100644 index 48cb2c3d6..000000000 --- a/src/main/resources/data/computercraft/recipes/monitor_advanced.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#G#", - "###" - ], - "key": { - "#": { - "tag": "c:gold_ingots" - }, - "G": { - "tag": "c:glass_panes" - } - }, - "result": { - "item": "computercraft:monitor_advanced", - "count": 4 - } -} diff --git a/src/main/resources/data/computercraft/recipes/monitor_normal.json b/src/main/resources/data/computercraft/recipes/monitor_normal.json deleted file mode 100644 index 93954505c..000000000 --- a/src/main/resources/data/computercraft/recipes/monitor_normal.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#G#", - "###" - ], - "key": { - "#": { - "tag": "c:stones" - }, - "G": { - "tag": "c:glass_panes" - } - }, - "result": { - "item": "computercraft:monitor_normal" - } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json b/src/main/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json deleted file mode 100644 index 26813f857..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_advanced", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_advanced" - }, - "P": { - "item": "computercraft:speaker" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced", - "nbt": "{Upgrade:\"computercraft:speaker\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json deleted file mode 100644 index 86b42d9c9..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_advanced", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_advanced" - }, - "P": { - "item": "computercraft:wireless_modem_advanced" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced", - "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json deleted file mode 100644 index f0f5ae53f..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_advanced", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_advanced" - }, - "P": { - "item": "computercraft:wireless_modem_normal" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced", - "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_computer_advanced.json b/src/main/resources/data/computercraft/recipes/pocket_computer_advanced.json deleted file mode 100644 index fefde5b00..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_computer_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#A#", - "#G#" - ], - "key": { - "#": { - "tag": "c:gold_ingots" - }, - "A": { - "item": "minecraft:golden_apple" - }, - "G": { - "tag": "c:glass_panes" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced" - } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_computer_normal.json b/src/main/resources/data/computercraft/recipes/pocket_computer_normal.json deleted file mode 100644 index 4f6a519db..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_computer_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#A#", - "#G#" - ], - "key": { - "#": { - "tag": "c:stones" - }, - "A": { - "item": "minecraft:golden_apple" - }, - "G": { - "tag": "c:glass_panes" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal" - } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_computer_upgrade.json b/src/main/resources/data/computercraft/recipes/pocket_computer_upgrade.json deleted file mode 100644 index 1dc7038c7..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_computer_upgrade.json +++ /dev/null @@ -1 +0,0 @@ -{ "type": "computercraft:pocket_computer_upgrade" } diff --git a/src/main/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json b/src/main/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json deleted file mode 100644 index 834c82670..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_normal", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_normal" - }, - "P": { - "item": "computercraft:speaker" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal", - "nbt": "{Upgrade:\"computercraft:speaker\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json deleted file mode 100644 index 732102efe..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_normal", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_normal" - }, - "P": { - "item": "computercraft:wireless_modem_advanced" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal", - "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json deleted file mode 100644 index a7e923bc1..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_normal", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_normal" - }, - "P": { - "item": "computercraft:wireless_modem_normal" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal", - "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/printed_book.json b/src/main/resources/data/computercraft/recipes/printed_book.json deleted file mode 100644 index aac7eb4e2..000000000 --- a/src/main/resources/data/computercraft/recipes/printed_book.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "ingredients": [ - { "item": "minecraft:leather" }, - { "item": "computercraft:printed_page" }, - { "item": "minecraft:string" } - ], - "result": { "item": "computercraft:printed_book" } -} diff --git a/src/main/resources/data/computercraft/recipes/printed_pages.json b/src/main/resources/data/computercraft/recipes/printed_pages.json deleted file mode 100644 index 38d32c223..000000000 --- a/src/main/resources/data/computercraft/recipes/printed_pages.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "ingredients": [ - { "item": "computercraft:printed_page" }, - { "item": "computercraft:printed_page" }, - { "item": "minecraft:string" } - ], - "result": { "item": "computercraft:printed_pages" } -} diff --git a/src/main/resources/data/computercraft/recipes/printer.json b/src/main/resources/data/computercraft/recipes/printer.json deleted file mode 100644 index 8ad853103..000000000 --- a/src/main/resources/data/computercraft/recipes/printer.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#R#", - "#D#" - ], - "key": { - "#": { - "tag": "c:stones" - }, - "R": { - "tag": "c:redstone_dusts" - }, - "D": [ - {"tag": "c:black_dyes"}, - {"tag": "c:blue_dyes"}, - {"tag": "c:brown_dyes"}, - {"tag": "c:cyan_dyes"}, - {"tag": "c:gray_dyes"}, - {"tag": "c:green_dyes"}, - {"tag": "c:light_blue_dyes"}, - {"tag": "c:light_gray_dyes"}, - {"tag": "c:lime_dyes"}, - {"tag": "c:magenta_dyes"}, - {"tag": "c:orange_dyes"}, - {"tag": "c:pink_dyes"}, - {"tag": "c:purple_dyes"}, - {"tag": "c:red_dyes"}, - {"tag": "c:white_dyes"}, - {"tag": "c:yellow_dyes"} - ] - }, - "result": { - "item": "computercraft:printer" - } -} diff --git a/src/main/resources/data/computercraft/recipes/printout.json b/src/main/resources/data/computercraft/recipes/printout.json deleted file mode 100644 index 20588569a..000000000 --- a/src/main/resources/data/computercraft/recipes/printout.json +++ /dev/null @@ -1 +0,0 @@ -{ "type": "computercraft:printout" } diff --git a/src/main/resources/data/computercraft/recipes/skull_cloudy.json b/src/main/resources/data/computercraft/recipes/skull_cloudy.json deleted file mode 100644 index 4d7a77642..000000000 --- a/src/main/resources/data/computercraft/recipes/skull_cloudy.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "crafting_shapeless", - "ingredients": [ - { "item": "minecraft:wither_skeleton_skull" }, - { "item": "computercraft:monitor_normal" } - ], - "result": { - "item": "minecraft:player_head", - "nbt": { "SkullOwner": { "Name": "Cloudhunter", "Id": "6d074736-b1e9-4378-a99b-bd8777821c9c" } } - } -} diff --git a/src/main/resources/data/computercraft/recipes/skull_dan200.json b/src/main/resources/data/computercraft/recipes/skull_dan200.json deleted file mode 100644 index 5f7bb84a8..000000000 --- a/src/main/resources/data/computercraft/recipes/skull_dan200.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "crafting_shapeless", - "ingredients": [ - { "item": "minecraft:wither_skeleton_skull" }, - { "item": "computercraft:computer_normal" } - ], - "result": { - "item": "minecraft:player_head", - "nbt": { "SkullOwner": { "Name": "dan200", "Id": "f3c8d69b-0776-4512-8434-d1b2165909eb" } } - } -} diff --git a/src/main/resources/data/computercraft/recipes/speaker.json b/src/main/resources/data/computercraft/recipes/speaker.json deleted file mode 100644 index 76570ce5a..000000000 --- a/src/main/resources/data/computercraft/recipes/speaker.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#N#", - "#R#" - ], - "key": { - "#": { - "tag": "c:stones" - }, - "N": { - "item": "minecraft:note_block" - }, - "R": { - "tag": "c:redstone_dusts" - } - }, - "result": { - "item": "computercraft:speaker" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json deleted file mode 100644 index 6976ec56f..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "computercraft:speaker" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"computercraft:speaker\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json deleted file mode 100644 index a78f7ee0d..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "computercraft:wireless_modem_advanced" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json deleted file mode 100644 index 362ed2b21..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "computercraft:wireless_modem_normal" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json deleted file mode 100644 index 0e4546f83..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "minecraft:crafting_table" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:crafting_table\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json deleted file mode 100644 index 03cb4a175..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "minecraft:diamond_axe" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_axe\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json deleted file mode 100644 index 2fc7dfa57..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "minecraft:diamond_hoe" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json deleted file mode 100644 index ef3601443..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "minecraft:diamond_pickaxe" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json deleted file mode 100644 index bea8b7268..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "minecraft:diamond_shovel" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json deleted file mode 100644 index 99609523f..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "minecraft:diamond_sword" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_sword\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/netherite_pickaxe.json b/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/netherite_pickaxe.json deleted file mode 100644 index 022f3fabd..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced/minecraft/netherite_pickaxe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_advanced" - }, - "T": { - "item": "minecraft:netherite_pickaxe" - } - }, - "result": { - "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:netherite_pickaxe\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json b/src/main/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json deleted file mode 100644 index 32741abaa..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "computercraft:speaker" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"computercraft:speaker\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json deleted file mode 100644 index 16e5ce57e..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "computercraft:wireless_modem_advanced" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json deleted file mode 100644 index 63c6c0ae4..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "computercraft:wireless_modem_normal" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json b/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json deleted file mode 100644 index a190856da..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "minecraft:crafting_table" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:crafting_table\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json b/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json deleted file mode 100644 index 10be7b2c7..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "minecraft:diamond_axe" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_axe\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json b/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json deleted file mode 100644 index 75ee73491..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "minecraft:diamond_hoe" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json b/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json deleted file mode 100644 index 8aca9926a..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "minecraft:diamond_pickaxe" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json b/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json deleted file mode 100644 index e9514e830..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "minecraft:diamond_shovel" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json b/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json deleted file mode 100644 index ff8719f0d..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "minecraft:diamond_sword" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_sword\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/netherite_pickaxe.json b/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/netherite_pickaxe.json deleted file mode 100644 index 8c70b6d6c..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_normal/minecraft/netherite_pickaxe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { - "item": "computercraft:turtle_normal" - }, - "T": { - "item": "minecraft:netherite_pickaxe" - } - }, - "result": { - "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:netherite_pickaxe\"}" - } -} diff --git a/src/main/resources/data/computercraft/recipes/turtle_upgrade.json b/src/main/resources/data/computercraft/recipes/turtle_upgrade.json deleted file mode 100644 index cf3b74e94..000000000 --- a/src/main/resources/data/computercraft/recipes/turtle_upgrade.json +++ /dev/null @@ -1 +0,0 @@ -{ "type": "computercraft:turtle_upgrade" } diff --git a/src/main/resources/data/computercraft/recipes/wired_modem.json b/src/main/resources/data/computercraft/recipes/wired_modem.json deleted file mode 100644 index 6b05f4698..000000000 --- a/src/main/resources/data/computercraft/recipes/wired_modem.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#R#", - "###" - ], - "key": { - "#": { - "tag": "c:stones" - }, - "R": { - "tag": "c:redstone_dusts" - } - }, - "result": { - "item": "computercraft:wired_modem" - } -} diff --git a/src/main/resources/data/computercraft/recipes/wired_modem_full_from.json b/src/main/resources/data/computercraft/recipes/wired_modem_full_from.json deleted file mode 100644 index b9016548b..000000000 --- a/src/main/resources/data/computercraft/recipes/wired_modem_full_from.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "minecraft:crafting_shapeless", - "ingredients": [ - { - "item": "computercraft:wired_modem" - } - ], - "result": { - "item": "computercraft:wired_modem_full" - } -} diff --git a/src/main/resources/data/computercraft/recipes/wired_modem_full_to.json b/src/main/resources/data/computercraft/recipes/wired_modem_full_to.json deleted file mode 100644 index 877ca24f4..000000000 --- a/src/main/resources/data/computercraft/recipes/wired_modem_full_to.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "minecraft:crafting_shapeless", - "ingredients": [ - { - "item": "computercraft:wired_modem_full" - } - ], - "result": { - "item": "computercraft:wired_modem" - } -} diff --git a/src/main/resources/data/computercraft/recipes/wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/wireless_modem_advanced.json deleted file mode 100644 index 8cddf9682..000000000 --- a/src/main/resources/data/computercraft/recipes/wireless_modem_advanced.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#E#", - "###" - ], - "key": { - "#": { - "tag": "c:gold_ingots" - }, - "E": { - "item": "minecraft:ender_eye" - } - }, - "result": { - "item": "computercraft:wireless_modem_advanced" - } -} diff --git a/src/main/resources/data/computercraft/recipes/wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/wireless_modem_normal.json deleted file mode 100644 index ddd1646dd..000000000 --- a/src/main/resources/data/computercraft/recipes/wireless_modem_normal.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "###", - "#E#", - "###" - ], - "key": { - "#": { - "tag": "c:stones" - }, - "E": { - "tag": "c:ender_pearls" - } - }, - "result": { - "item": "computercraft:wireless_modem_normal" - } -} diff --git a/src/main/resources/data/computercraft/tags/blocks/computer.json b/src/main/resources/data/computercraft/tags/blocks/computer.json deleted file mode 100644 index 533f54dd1..000000000 --- a/src/main/resources/data/computercraft/tags/blocks/computer.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "replace": false, - "values": [ - "computercraft:computer_normal", - "computercraft:computer_advanced", - "computercraft:computer_command" - ] -} diff --git a/src/main/resources/data/computercraft/tags/blocks/monitor.json b/src/main/resources/data/computercraft/tags/blocks/monitor.json deleted file mode 100644 index 8a05bcbef..000000000 --- a/src/main/resources/data/computercraft/tags/blocks/monitor.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "replace": false, - "values": [ - "computercraft:monitor_normal", - "computercraft:monitor_advanced" - ] -} diff --git a/src/main/resources/data/computercraft/tags/blocks/turtle.json b/src/main/resources/data/computercraft/tags/blocks/turtle.json deleted file mode 100644 index 03d07a8cd..000000000 --- a/src/main/resources/data/computercraft/tags/blocks/turtle.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "replace": false, - "values": [ - "computercraft:turtle_normal", - "computercraft:turtle_advanced" - ] -} diff --git a/src/main/resources/data/computercraft/tags/blocks/wired_modem.json b/src/main/resources/data/computercraft/tags/blocks/wired_modem.json deleted file mode 100644 index 19b5ee97d..000000000 --- a/src/main/resources/data/computercraft/tags/blocks/wired_modem.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "replace": false, - "values": [ - "computercraft:cable", - "computercraft:wired_modem_full" - ] -} diff --git a/src/main/resources/data/computercraft/tags/items/computer.json b/src/main/resources/data/computercraft/tags/items/computer.json deleted file mode 100644 index 533f54dd1..000000000 --- a/src/main/resources/data/computercraft/tags/items/computer.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "replace": false, - "values": [ - "computercraft:computer_normal", - "computercraft:computer_advanced", - "computercraft:computer_command" - ] -} diff --git a/src/main/resources/data/computercraft/tags/items/monitor.json b/src/main/resources/data/computercraft/tags/items/monitor.json deleted file mode 100644 index 8a05bcbef..000000000 --- a/src/main/resources/data/computercraft/tags/items/monitor.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "replace": false, - "values": [ - "computercraft:monitor_normal", - "computercraft:monitor_advanced" - ] -} diff --git a/src/main/resources/data/computercraft/tags/items/turtle.json b/src/main/resources/data/computercraft/tags/items/turtle.json deleted file mode 100644 index 03d07a8cd..000000000 --- a/src/main/resources/data/computercraft/tags/items/turtle.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "replace": false, - "values": [ - "computercraft:turtle_normal", - "computercraft:turtle_advanced" - ] -} diff --git a/src/main/resources/data/computercraft/tags/items/wired_modem.json b/src/main/resources/data/computercraft/tags/items/wired_modem.json deleted file mode 100644 index be62458d8..000000000 --- a/src/main/resources/data/computercraft/tags/items/wired_modem.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "replace": false, - "values": [ - "computercraft:wired_modem", - "computercraft:wired_modem_full" - ] -} diff --git a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json deleted file mode 100644 index 84f9f8953..000000000 --- a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "replace": false, - "values": [ - "computercraft:monitor_normal", - "computercraft:monitor_advanced", - "computercraft:computer_normal", - "computercraft:computer_advanced", - "computercraft:computer_command", - "computercraft:turtle_normal", - "computercraft:turtle_advanced", - "computercraft:speaker", - "computercraft:disk_drive", - "computercraft:printer", - "computercraft:wireless_modem_normal", - "computercraft:wireless_modem_advanced", - "computercraft:wired_modem_full", - "computercraft:cable" - ] -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 41a8330bb..d42d28808 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -22,8 +22,8 @@ ], "depends": { "minecraft": ">=1.18.2-rc.1 <1.19", - "fabricloader": ">=0.12.9", - "fabric": "*" + "fabricloader": ">=0.13.3", + "fabric": ">=0.51.1" }, "suggests": { "modmenu": "*" @@ -32,13 +32,16 @@ "environment": "*", "entrypoints": { "main": [ - "dan200.computercraft.ComputerCraft" + "dan200.computercraft.ComputerCraft::onInitialize" ], "client": [ "dan200.computercraft.client.proxy.ComputerCraftProxyClient" ], "modmenu": [ "dan200.computercraft.shared.integration.ModMenuIntegration" + ], + "fabric-datagen": [ + "dan200.computercraft.data.Generators" ] }, "mixins": [ diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index a6665f9e4..5726da7e4 100755 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { - "pack_format": 4, - "description": "CC:T for Fabric" + "pack_format": 9, + "description": "CC: Restitched" } } diff --git a/src/main/resources/resourcepacks/overhaul b/src/main/resources/resourcepacks/overhaul index 8785fe249..02485736d 160000 --- a/src/main/resources/resourcepacks/overhaul +++ b/src/main/resources/resourcepacks/overhaul @@ -1 +1 @@ -Subproject commit 8785fe24967be1b8628de834fa6ba387d2ab2d7a +Subproject commit 02485736d0bf1ea3803d7d43e68225310bdea69e diff --git a/src/test/java/dan200/computercraft/ContramapMatcher.java b/src/test/java/dan200/computercraft/ContramapMatcher.java new file mode 100644 index 000000000..5126ef280 --- /dev/null +++ b/src/test/java/dan200/computercraft/ContramapMatcher.java @@ -0,0 +1,53 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +import java.util.function.Function; + +public class ContramapMatcher extends TypeSafeDiagnosingMatcher +{ + private final String desc; + private final Function convert; + private final Matcher matcher; + + public ContramapMatcher( String desc, Function convert, Matcher matcher ) + { + this.desc = desc; + this.convert = convert; + this.matcher = matcher; + } + + @Override + protected boolean matchesSafely( T item, Description mismatchDescription ) + { + U converted = convert.apply( item ); + if( matcher.matches( converted ) ) return true; + + mismatchDescription.appendText( desc ).appendText( " " ); + matcher.describeMismatch( converted, mismatchDescription ); + return false; + } + + @Override + public void describeTo( Description description ) + { + description.appendText( desc ).appendText( " " ).appendDescriptionOf( matcher ); + } + + public static Matcher contramap( Matcher matcher, String desc, Function convert ) + { + return new ContramapMatcher<>( desc, convert, matcher ); + } + + public static Matcher contramap( Matcher matcher, Function convert ) + { + return new ContramapMatcher<>( "-f(_)->", convert, matcher ); + } +} diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java new file mode 100644 index 000000000..1f95865bf --- /dev/null +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -0,0 +1,503 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.ILuaAPI; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.computer.BasicEnvironment; +import dan200.computercraft.core.computer.Computer; +import dan200.computercraft.core.computer.ComputerSide; +import dan200.computercraft.core.computer.MainThread; +import dan200.computercraft.core.filesystem.FileMount; +import dan200.computercraft.core.filesystem.FileSystemException; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.peripheral.modem.ModemState; +import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.function.Executable; +import org.opentest4j.AssertionFailedError; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.Writer; +import java.nio.channels.Channels; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static dan200.computercraft.api.lua.LuaValues.getType; + +/** + * Loads tests from {@code test-rom/spec} and executes them. + * + * This spins up a new computer and runs the {@code mcfly.lua} script. This will then load all files in the {@code spec} + * directory and register them with {@code cct_test.start}. + * + * From the test names, we generate a tree of {@link DynamicNode}s which queue an event and wait for + * {@code cct_test.submit} to be called. McFly pulls these events, executes the tests and then calls the submit method. + * + * Once all tests are done, we invoke {@code cct_test.finish} in order to mark everything as complete. + */ +public class ComputerTestDelegate +{ + private static final File REPORT_PATH = new File( "test-files/luacov.report.out" ); + + private static final Logger LOG = LogManager.getLogger( ComputerTestDelegate.class ); + + private static final long TICK_TIME = TimeUnit.MILLISECONDS.toNanos( 50 ); + + private static final long TIMEOUT = TimeUnit.SECONDS.toNanos( 10 ); + + private static final Set SKIP_KEYWORDS = new HashSet<>( + Arrays.asList( System.getProperty( "cc.skip_keywords", "" ).split( "," ) ) + ); + + private static final Pattern KEYWORD = Pattern.compile( ":([a-z_]+)" ); + + private final ReentrantLock lock = new ReentrantLock(); + private Computer computer; + + private final Condition hasTests = lock.newCondition(); + private DynamicNodeBuilder tests; + + private final Condition hasRun = lock.newCondition(); + private String currentTest; + private boolean runFinished; + private Throwable runResult; + + private final Condition hasFinished = lock.newCondition(); + private boolean finished = false; + private Map> finishedWith; + + @BeforeEach + public void before() throws IOException + { + ComputerCraft.logComputerErrors = true; + + if( REPORT_PATH.delete() ) ComputerCraft.log.info( "Deleted previous coverage report." ); + + Terminal term = new Terminal( 80, 100 ); + IWritableMount mount = new FileMount( new File( "test-files/mount" ), 10_000_000 ); + + // Remove any existing files + List children = new ArrayList<>(); + mount.list( "", children ); + for( String child : children ) mount.delete( child ); + + // And add our startup file + try( WritableByteChannel channel = mount.openForWrite( "startup.lua" ); + Writer writer = Channels.newWriter( channel, StandardCharsets.UTF_8.newEncoder(), -1 ) ) + { + writer.write( "loadfile('test-rom/mcfly.lua', nil, _ENV)('test-rom/spec') cct_test.finish()" ); + } + + computer = new Computer( new BasicEnvironment( mount ), term, 0 ); + computer.getEnvironment().setPeripheral( ComputerSide.TOP, new FakeModem() ); + computer.addApi( new CctTestAPI() ); + + computer.turnOn(); + } + + @AfterEach + public void after() throws InterruptedException, IOException + { + try + { + LOG.info( "Finished execution" ); + computer.queueEvent( "cct_test_run", null ); + + // Wait for test execution to fully finish + lock.lockInterruptibly(); + try + { + long remaining = TIMEOUT; + while( remaining > 0 && !finished ) + { + tick(); + if( hasFinished.awaitNanos( TICK_TIME ) > 0 ) break; + remaining -= TICK_TIME; + } + + if( remaining <= 0 ) throw new IllegalStateException( "Timed out waiting for finish." + dump() ); + if( !finished ) throw new IllegalStateException( "Computer did not finish." + dump() ); + } + finally + { + lock.unlock(); + } + } + finally + { + // Show a dump of computer output + System.out.println( dump() ); + + // And shutdown + computer.shutdown(); + } + + if( finishedWith != null ) + { + REPORT_PATH.getParentFile().mkdirs(); + try( BufferedWriter writer = Files.newBufferedWriter( REPORT_PATH.toPath() ) ) + { + new LuaCoverage( finishedWith ).write( writer ); + } + } + } + + @TestFactory + public Stream get() throws InterruptedException + { + lock.lockInterruptibly(); + try + { + long remaining = TIMEOUT; + while( remaining > 0 & tests == null ) + { + tick(); + if( hasTests.awaitNanos( TICK_TIME ) > 0 ) break; + remaining -= TICK_TIME; + } + + if( remaining <= 0 ) throw new IllegalStateException( "Timed out waiting for tests. " + dump() ); + if( tests == null ) throw new IllegalStateException( "Computer did not provide any tests. " + dump() ); + } + finally + { + lock.unlock(); + } + + return tests.buildChildren(); + } + + private static class DynamicNodeBuilder + { + private final String name; + private final Map children; + private final Executable executor; + + DynamicNodeBuilder( String name ) + { + this.name = name; + this.children = new HashMap<>(); + this.executor = null; + } + + DynamicNodeBuilder( String name, Executable executor ) + { + this.name = name; + this.children = Collections.emptyMap(); + this.executor = executor; + } + + DynamicNodeBuilder get( String name ) + { + DynamicNodeBuilder child = children.get( name ); + if( child == null ) children.put( name, child = new DynamicNodeBuilder( name ) ); + return child; + } + + void runs( String name, Executable executor ) + { + if( this.executor != null ) throw new IllegalStateException( name + " is leaf node" ); + if( children.containsKey( name ) ) throw new IllegalStateException( "Duplicate key for " + name ); + + children.put( name, new DynamicNodeBuilder( name, executor ) ); + } + + boolean isActive() + { + Matcher matcher = KEYWORD.matcher( name ); + while( matcher.find() ) + { + if( SKIP_KEYWORDS.contains( matcher.group( 1 ) ) ) return false; + } + + return true; + } + + DynamicNode build() + { + return executor == null + ? DynamicContainer.dynamicContainer( name, buildChildren() ) + : DynamicTest.dynamicTest( name, executor ); + } + + Stream buildChildren() + { + return children.values().stream() + .filter( DynamicNodeBuilder::isActive ) + .map( DynamicNodeBuilder::build ); + } + } + + private String dump() + { + if( !computer.isOn() ) return "Computer is currently off."; + + Terminal term = computer.getAPIEnvironment().getTerminal(); + StringBuilder builder = new StringBuilder().append( "Computer is currently on.\n" ); + + for( int line = 0; line < term.getHeight(); line++ ) + { + builder.append( String.format( "%2d | %" + term.getWidth() + "s |\n", line + 1, term.getLine( line ) ) ); + } + + computer.shutdown(); + return builder.toString(); + } + + private void tick() + { + computer.tick(); + MainThread.executePendingTasks(); + } + + private static String formatName( String name ) + { + return name.replace( "\0", " -> " ); + } + + private static class FakeModem extends WirelessModemPeripheral + { + FakeModem() + { + super( new ModemState(), true ); + } + + @Nonnull + @Override + @SuppressWarnings( "ConstantConditions" ) + public Level getLevel() + { + return null; + } + + @Nonnull + @Override + public Vec3 getPosition() + { + return Vec3.ZERO; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } + + public class CctTestAPI implements ILuaAPI + { + @Override + public String[] getNames() + { + return new String[] { "cct_test" }; + } + + @Override + public void startup() + { + try + { + computer.getAPIEnvironment().getFileSystem().mount( + "test-rom", "test-rom", + BasicEnvironment.createMount( ComputerTestDelegate.class, "test-rom", "test" ) + ); + } + catch( FileSystemException e ) + { + throw new IllegalStateException( e ); + } + } + + @LuaFunction + public final void start( Map tests ) throws LuaException + { + // Submit several tests and signal for #get to run + LOG.info( "Received tests from computer" ); + DynamicNodeBuilder root = new DynamicNodeBuilder( "" ); + for( Object key : tests.keySet() ) + { + if( !(key instanceof String name) ) throw new LuaException( "Non-key string " + getType( key ) ); + + String[] parts = name.split( "\0" ); + DynamicNodeBuilder builder = root; + for( int i = 0; i < parts.length - 1; i++ ) builder = builder.get( parts[i] ); + builder.runs( parts[parts.length - 1], () -> { + // Run it + lock.lockInterruptibly(); + try + { + // Set the current test + runResult = null; + runFinished = false; + currentTest = name; + + // Tell the computer to run it + LOG.info( "Starting '{}'", formatName( name ) ); + computer.queueEvent( "cct_test_run", new Object[] { name } ); + + long remaining = TIMEOUT; + while( remaining > 0 && computer.isOn() && !runFinished ) + { + tick(); + + long waiting = hasRun.awaitNanos( TICK_TIME ); + if( waiting > 0 ) break; + remaining -= TICK_TIME; + } + + LOG.info( "Finished '{}'", formatName( name ) ); + + if( remaining <= 0 ) + { + throw new IllegalStateException( "Timed out waiting for test" ); + } + else if( !computer.isOn() ) + { + throw new IllegalStateException( "Computer turned off mid-execution" ); + } + + if( runResult != null ) throw runResult; + } + finally + { + lock.unlock(); + currentTest = null; + } + } ); + } + + try + { + lock.lockInterruptibly(); + } + catch( InterruptedException e ) + { + throw new RuntimeException( e ); + } + try + { + ComputerTestDelegate.this.tests = root; + hasTests.signal(); + } + finally + { + lock.unlock(); + } + } + + @LuaFunction + public final void submit( Map tbl ) + { + // Submit the result of a test, allowing the test executor to continue + String name = (String) tbl.get( "name" ); + if( name == null ) + { + ComputerCraft.log.error( "Oh no: {}", tbl ); + } + String status = (String) tbl.get( "status" ); + String message = (String) tbl.get( "message" ); + String trace = (String) tbl.get( "trace" ); + + StringBuilder wholeMessage = new StringBuilder(); + if( message != null ) wholeMessage.append( message ); + if( trace != null ) + { + if( wholeMessage.length() != 0 ) wholeMessage.append( '\n' ); + wholeMessage.append( trace ); + } + + try + { + lock.lockInterruptibly(); + } + catch( InterruptedException e ) + { + throw new RuntimeException( e ); + } + try + { + LOG.info( "'{}' finished with {}", formatName( name ), status ); + + // Skip if a test mismatch + if( !name.equals( currentTest ) ) + { + LOG.warn( "Skipping test '{}', as we're currently executing '{}'", formatName( name ), formatName( currentTest ) ); + return; + } + + switch( status ) + { + case "ok": + case "pending": + break; + case "fail": + runResult = new AssertionFailedError( wholeMessage.toString() ); + break; + case "error": + runResult = new IllegalStateException( wholeMessage.toString() ); + break; + } + + runFinished = true; + hasRun.signal(); + } + finally + { + lock.unlock(); + } + } + + @LuaFunction + public final void finish( Optional> result ) + { + @SuppressWarnings( "unchecked" ) + Map> finishedResult = (Map>) result.orElse( null ); + LOG.info( "Finished" ); + + // Signal to after that execution has finished + try + { + lock.lockInterruptibly(); + } + catch( InterruptedException e ) + { + throw new RuntimeException( e ); + } + try + { + finished = true; + if( finishedResult != null ) finishedWith = finishedResult; + + hasFinished.signal(); + } + finally + { + lock.unlock(); + } + } + } +} diff --git a/src/test/java/dan200/computercraft/core/LuaCoverage.java b/src/test/java/dan200/computercraft/core/LuaCoverage.java new file mode 100644 index 000000000..28435f001 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/LuaCoverage.java @@ -0,0 +1,157 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core; + +import com.google.common.base.Strings; +import dan200.computercraft.ComputerCraft; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import org.squiddev.cobalt.Prototype; +import org.squiddev.cobalt.compiler.CompileException; +import org.squiddev.cobalt.compiler.LuaC; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class LuaCoverage +{ + private static final Path ROOT = new File( "src/main/resources/data/computercraft/lua" ).toPath(); + private static final Path BIOS = ROOT.resolve( "bios.lua" ); + private static final Path APIS = ROOT.resolve( "rom/apis" ); + private static final Path SHELL = ROOT.resolve( "rom/programs/shell.lua" ); + private static final Path MULTISHELL = ROOT.resolve( "rom/programs/advanced/multishell.lua" ); + private static final Path TREASURE = ROOT.resolve( "treasure" ); + + private final Map> coverage; + private final String blank; + private final String zero; + private final String countFormat; + + LuaCoverage( Map> coverage ) + { + this.coverage = coverage; + + int max = (int) coverage.values().stream() + .flatMapToDouble( x -> x.values().stream().mapToDouble( y -> y ) ) + .max().orElse( 0 ); + int maxLen = Math.max( 1, (int) Math.ceil( Math.log10( max ) ) ); + blank = Strings.repeat( " ", maxLen + 1 ); + zero = Strings.repeat( "*", maxLen ) + "0"; + countFormat = "%" + (maxLen + 1) + "d"; + } + + void write( Writer out ) throws IOException + { + Files.find( ROOT, Integer.MAX_VALUE, ( path, attr ) -> attr.isRegularFile() && !path.startsWith( TREASURE ) ).forEach( path -> { + Path relative = ROOT.relativize( path ); + String full = relative.toString().replace( '\\', '/' ); + if( !full.endsWith( ".lua" ) ) return; + + Map files = Stream.of( + coverage.remove( "/" + full ), + path.equals( BIOS ) ? coverage.remove( "bios.lua" ) : null, + path.equals( SHELL ) ? coverage.remove( "shell.lua" ) : null, + path.equals( MULTISHELL ) ? coverage.remove( "multishell.lua" ) : null, + path.startsWith( APIS ) ? coverage.remove( path.getFileName().toString() ) : null + ) + .filter( Objects::nonNull ) + .flatMap( x -> x.entrySet().stream() ) + .collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, Double::sum ) ); + + try + { + writeCoverageFor( out, path, files ); + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + } ); + + for( String filename : coverage.keySet() ) + { + if( filename.startsWith( "/test-rom/" ) ) continue; + ComputerCraft.log.warn( "Unknown file {}", filename ); + } + } + + private void writeCoverageFor( Writer out, Path fullName, Map visitedLines ) throws IOException + { + if( !Files.exists( fullName ) ) + { + ComputerCraft.log.error( "Cannot locate file {}", fullName ); + return; + } + + IntSet activeLines = getActiveLines( fullName.toFile() ); + + out.write( "==============================================================================\n" ); + out.write( fullName.toString().replace( '\\', '/' ) ); + out.write( "\n" ); + out.write( "==============================================================================\n" ); + + try( BufferedReader reader = Files.newBufferedReader( fullName ) ) + { + String line; + int lineNo = 0; + while( (line = reader.readLine()) != null ) + { + lineNo++; + Double count = visitedLines.get( (double) lineNo ); + if( count != null ) + { + out.write( String.format( countFormat, count.intValue() ) ); + } + else if( activeLines.contains( lineNo ) ) + { + out.write( zero ); + } + else + { + out.write( blank ); + } + + out.write( ' ' ); + out.write( line ); + out.write( "\n" ); + } + } + } + + private static IntSet getActiveLines( File file ) throws IOException + { + IntSet activeLines = new IntOpenHashSet(); + try( InputStream stream = new FileInputStream( file ) ) + { + Prototype proto = LuaC.compile( stream, "@" + file.getPath() ); + Queue queue = new ArrayDeque<>(); + queue.add( proto ); + + while( (proto = queue.poll()) != null ) + { + int[] lines = proto.lineinfo; + if( lines != null ) + { + for( int line : lines ) + { + activeLines.add( line ); + } + } + if( proto.p != null ) Collections.addAll( queue, proto.p ); + } + } + catch( CompileException e ) + { + throw new IllegalStateException( "Cannot compile", e ); + } + + return activeLines; + } +} diff --git a/src/test/java/dan200/computercraft/core/apis/AsyncRunner.kt b/src/test/java/dan200/computercraft/core/apis/AsyncRunner.kt new file mode 100644 index 000000000..fd976eedb --- /dev/null +++ b/src/test/java/dan200/computercraft/core/apis/AsyncRunner.kt @@ -0,0 +1,121 @@ +package dan200.computercraft.core.apis + +import dan200.computercraft.ComputerCraft +import dan200.computercraft.api.lua.ILuaAPI +import dan200.computercraft.api.lua.MethodResult +import dan200.computercraft.api.peripheral.IPeripheral +import dan200.computercraft.api.peripheral.IWorkMonitor +import dan200.computercraft.core.computer.BasicEnvironment +import dan200.computercraft.core.computer.ComputerSide +import dan200.computercraft.core.computer.IComputerEnvironment +import dan200.computercraft.core.filesystem.FileSystem +import dan200.computercraft.core.terminal.Terminal +import dan200.computercraft.core.tracking.TrackingField +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds +import kotlin.time.ExperimentalTime + + +abstract class NullApiEnvironment : IAPIEnvironment { + private val computerEnv = BasicEnvironment() + + override fun getComputerID(): Int = 0 + override fun getComputerEnvironment(): IComputerEnvironment = computerEnv + override fun getMainThreadMonitor(): IWorkMonitor = throw IllegalStateException("Work monitor not available") + override fun getTerminal(): Terminal = throw IllegalStateException("Terminal not available") + override fun getFileSystem(): FileSystem = throw IllegalStateException("Terminal not available") + override fun shutdown() {} + override fun reboot() {} + override fun setOutput(side: ComputerSide?, output: Int) {} + override fun getOutput(side: ComputerSide?): Int = 0 + override fun getInput(side: ComputerSide?): Int = 0 + override fun setBundledOutput(side: ComputerSide?, output: Int) {} + override fun getBundledOutput(side: ComputerSide?): Int = 0 + override fun getBundledInput(side: ComputerSide?): Int = 0 + override fun setPeripheralChangeListener(listener: IAPIEnvironment.IPeripheralChangeListener?) {} + override fun getPeripheral(side: ComputerSide?): IPeripheral? = null + override fun getLabel(): String? = null + override fun setLabel(label: String?) {} + override fun startTimer(ticks: Long): Int = 0 + override fun cancelTimer(id: Int) {} + override fun addTrackingChange(field: TrackingField, change: Long) {} +} + +class EventResult(val name: String, val args: Array) + +class AsyncRunner : NullApiEnvironment() { + private val eventStream: Channel> = Channel(Int.MAX_VALUE) + private val apis: MutableList = mutableListOf() + + override fun queueEvent(event: String?, vararg args: Any?) { + ComputerCraft.log.debug("Queue event $event ${args.contentToString()}") + if (eventStream.trySend(arrayOf(event, *args)).isFailure) { + throw IllegalStateException("Queue is full") + } + } + + override fun shutdown() { + super.shutdown() + eventStream.close() + apis.forEach { it.shutdown() } + } + + fun addApi(api: T): T { + apis.add(api) + api.startup() + return api + } + + suspend fun resultOf(toRun: MethodResult): Array { + var running = toRun + while (running.callback != null) running = runOnce(running) + return running.result ?: empty + } + + private suspend fun runOnce(obj: MethodResult): MethodResult { + val callback = obj.callback ?: throw NullPointerException("Callback cannot be null") + + val result = obj.result + val filter: String? = if (result.isNullOrEmpty() || result[0] !is String) { + null + } else { + result[0] as String + } + + return callback.resume(pullEventImpl(filter)) + } + + private suspend fun pullEventImpl(filter: String?): Array { + for (event in eventStream) { + ComputerCraft.log.debug("Pulled event ${event.contentToString()}") + val eventName = event[0] as String + if (filter == null || eventName == filter || eventName == "terminate") return event + } + + throw IllegalStateException("No more events") + } + + suspend fun pullEvent(filter: String? = null): EventResult { + val result = pullEventImpl(filter) + return EventResult(result[0] as String, result.copyOfRange(1, result.size)) + } + + companion object { + private val empty: Array = arrayOf() + + @OptIn(ExperimentalTime::class) + fun runTest(timeout: Duration = Duration.seconds(5), fn: suspend AsyncRunner.() -> Unit) { + runBlocking { + val runner = AsyncRunner() + try { + withTimeout(timeout) { fn(runner) } + } finally { + runner.shutdown() + } + } + } + } +} diff --git a/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java b/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java new file mode 100644 index 000000000..19e743ae3 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java @@ -0,0 +1,67 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.apis; + +import dan200.computercraft.api.lua.*; +import dan200.computercraft.core.asm.LuaMethod; +import dan200.computercraft.core.asm.NamedMethod; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class ObjectWrapper implements ILuaContext +{ + private final Object object; + private final Map methodMap; + + public ObjectWrapper( Object object ) + { + this.object = object; + String[] dynamicMethods = object instanceof IDynamicLuaObject dynamic + ? Objects.requireNonNull( dynamic.getMethodNames(), "Methods cannot be null" ) + : LuaMethod.EMPTY_METHODS; + + List> methods = LuaMethod.GENERATOR.getMethods( object.getClass() ); + + Map methodMap = this.methodMap = new HashMap<>( methods.size() + dynamicMethods.length ); + for( int i = 0; i < dynamicMethods.length; i++ ) + { + methodMap.put( dynamicMethods[i], LuaMethod.DYNAMIC.get( i ) ); + } + for( NamedMethod method : methods ) + { + methodMap.put( method.getName(), method.getMethod() ); + } + } + + public Object[] call( String name, Object... args ) throws LuaException + { + LuaMethod method = methodMap.get( name ); + if( method == null ) throw new IllegalStateException( "No such method '" + name + "'" ); + + return method.apply( object, this, new ObjectArguments( args ) ).getResult(); + } + + @SuppressWarnings( "unchecked" ) + public T callOf( String name, Object... args ) throws LuaException + { + return (T) call( name, args )[0]; + } + + public T callOf( Class klass, String name, Object... args ) throws LuaException + { + return klass.cast( call( name, args )[0] ); + } + + @Override + public long issueMainThreadTask( @Nonnull ILuaTask task ) + { + throw new IllegalStateException( "Method should never queue events" ); + } +} diff --git a/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java b/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java new file mode 100644 index 000000000..172ae4c83 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java @@ -0,0 +1,86 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.apis.handles; + +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.core.apis.ObjectWrapper; +import org.junit.jupiter.api.Test; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +public class BinaryReadableHandleTest +{ + @Test + public void testReadChar() throws LuaException + { + ObjectWrapper wrapper = fromLength( 5 ); + assertEquals( 'A', (int) wrapper.callOf( Integer.class, "read" ) ); + } + + @Test + public void testReadShortComplete() throws LuaException + { + ObjectWrapper wrapper = fromLength( 10 ); + assertEquals( 5, wrapper.callOf( "read", 5 ).remaining() ); + } + + @Test + public void testReadShortPartial() throws LuaException + { + ObjectWrapper wrapper = fromLength( 5 ); + assertEquals( 5, wrapper.callOf( "read", 10 ).remaining() ); + } + + @Test + public void testReadLongComplete() throws LuaException + { + ObjectWrapper wrapper = fromLength( 10000 ); + assertEquals( 9000, wrapper.callOf( "read", 9000 ).length ); + } + + @Test + public void testReadLongPartial() throws LuaException + { + ObjectWrapper wrapper = fromLength( 10000 ); + assertEquals( 10000, wrapper.callOf( "read", 11000 ).length ); + } + + @Test + public void testReadLongPartialSmaller() throws LuaException + { + ObjectWrapper wrapper = fromLength( 1000 ); + assertEquals( 1000, wrapper.callOf( "read", 11000 ).remaining() ); + } + + @Test + public void testReadLine() throws LuaException + { + ObjectWrapper wrapper = new ObjectWrapper( BinaryReadableHandle.of( new ArrayByteChannel( "hello\r\nworld\r!".getBytes( StandardCharsets.UTF_8 ) ) ) ); + assertArrayEquals( "hello".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine" ) ); + assertArrayEquals( "world\r!".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine" ) ); + assertNull( wrapper.call( "readLine" ) ); + } + + @Test + public void testReadLineTrailing() throws LuaException + { + ObjectWrapper wrapper = new ObjectWrapper( BinaryReadableHandle.of( new ArrayByteChannel( "hello\r\nworld\r!".getBytes( StandardCharsets.UTF_8 ) ) ) ); + assertArrayEquals( "hello\r\n".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine", true ) ); + assertArrayEquals( "world\r!".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine", true ) ); + assertNull( wrapper.call( "readLine", true ) ); + } + + private static ObjectWrapper fromLength( int length ) + { + byte[] input = new byte[length]; + Arrays.fill( input, (byte) 'A' ); + return new ObjectWrapper( BinaryReadableHandle.of( new ArrayByteChannel( input ) ) ); + } +} diff --git a/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java b/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java new file mode 100644 index 000000000..7028a12d8 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java @@ -0,0 +1,69 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.apis.handles; + +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.core.apis.ObjectWrapper; +import org.junit.jupiter.api.Test; + +import java.io.BufferedReader; +import java.io.CharArrayReader; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class EncodedReadableHandleTest +{ + @Test + public void testReadChar() throws LuaException + { + ObjectWrapper wrapper = fromLength( 5 ); + assertEquals( "A", wrapper.callOf( "read" ) ); + } + + @Test + public void testReadShortComplete() throws LuaException + { + ObjectWrapper wrapper = fromLength( 10 ); + assertEquals( "AAAAA", wrapper.callOf( "read", 5 ) ); + } + + @Test + public void testReadShortPartial() throws LuaException + { + ObjectWrapper wrapper = fromLength( 5 ); + assertEquals( "AAAAA", wrapper.callOf( "read", 10 ) ); + } + + + @Test + public void testReadLongComplete() throws LuaException + { + ObjectWrapper wrapper = fromLength( 10000 ); + assertEquals( 9000, wrapper.callOf( "read", 9000 ).length() ); + } + + @Test + public void testReadLongPartial() throws LuaException + { + ObjectWrapper wrapper = fromLength( 10000 ); + assertEquals( 10000, wrapper.callOf( "read", 11000 ).length() ); + } + + @Test + public void testReadLongPartialSmaller() throws LuaException + { + ObjectWrapper wrapper = fromLength( 1000 ); + assertEquals( 1000, wrapper.callOf( "read", 11000 ).length() ); + } + + private static ObjectWrapper fromLength( int length ) + { + char[] input = new char[length]; + Arrays.fill( input, 'A' ); + return new ObjectWrapper( new EncodedReadableHandle( new BufferedReader( new CharArrayReader( input ) ) ) ); + } +} diff --git a/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java b/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java new file mode 100644 index 000000000..77701b5d1 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java @@ -0,0 +1,47 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.apis.http.options; + +import dan200.computercraft.ComputerCraft; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.net.InetSocketAddress; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AddressRuleTest +{ + @Test + public void matchesPort() + { + Iterable rules = Collections.singletonList( AddressRule.parse( + "127.0.0.1", 8080, + new PartialOptions( Action.ALLOW, null, null, null, null ) + ) ); + + assertEquals( apply( rules, "localhost", 8080 ).action, Action.ALLOW ); + assertEquals( apply( rules, "localhost", 8081 ).action, Action.DENY ); + } + + @ParameterizedTest + @ValueSource( strings = { + "0.0.0.0", "[::]", + "localhost", "127.0.0.1.nip.io", "127.0.0.1", "[::1]", + "172.17.0.1", "192.168.1.114", "[0:0:0:0:0:ffff:c0a8:172]", "10.0.0.1" + } ) + public void blocksLocalDomains( String domain ) + { + assertEquals( apply( ComputerCraft.httpRules, domain, 80 ).action, Action.DENY ); + } + + private Options apply( Iterable rules, String host, int port ) + { + return AddressRule.apply( rules, host, new InetSocketAddress( host, port ) ); + } +} diff --git a/src/test/java/dan200/computercraft/core/apis/http/options/TestHttpApi.kt b/src/test/java/dan200/computercraft/core/apis/http/options/TestHttpApi.kt new file mode 100644 index 000000000..206924cc0 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/apis/http/options/TestHttpApi.kt @@ -0,0 +1,51 @@ +package dan200.computercraft.core.apis.http.options + +import dan200.computercraft.ComputerCraft +import dan200.computercraft.core.apis.AsyncRunner +import dan200.computercraft.core.apis.HTTPAPI +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions.assertArrayEquals +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import java.util.* + +@Disabled("Requires some setup locally.") +class TestHttpApi { + companion object { + private const val WS_ADDRESS = "ws://127.0.0.1:8080" + + @JvmStatic + @BeforeAll + fun before() { + ComputerCraft.httpRules = listOf(AddressRule.parse("*", null, Action.ALLOW.toPartial())) + } + + @JvmStatic + @AfterAll + fun after() { + ComputerCraft.httpRules = Collections.unmodifiableList( + listOf( + AddressRule.parse("\$private", null, Action.DENY.toPartial()), + AddressRule.parse("*", null, Action.ALLOW.toPartial()) + ) + ) + } + } + + @Test + fun `Connects to websocket`() { + AsyncRunner.runTest { + val httpApi = addApi(HTTPAPI(this)) + + val result = httpApi.websocket(WS_ADDRESS, Optional.empty()) + assertArrayEquals(arrayOf(true), result, "Should have created websocket") + + val event = pullEvent() + assertEquals("websocket_success", event.name) { + "Websocket failed to connect: ${event.args.contentToString()}" + } + } + } +} diff --git a/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java b/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java new file mode 100644 index 000000000..51e98d257 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java @@ -0,0 +1,282 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.asm; + +import dan200.computercraft.api.lua.*; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.core.computer.ComputerSide; +import org.hamcrest.Matcher; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static dan200.computercraft.ContramapMatcher.contramap; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class GeneratorTest +{ + @Test + public void testBasic() + { + List> methods = LuaMethod.GENERATOR.getMethods( Basic.class ); + assertThat( methods, contains( + allOf( + named( "go" ), + contramap( is( true ), "non-yielding", NamedMethod::nonYielding ) + ) + ) ); + } + + @Test + public void testIdentical() + { + List> methods = LuaMethod.GENERATOR.getMethods( Basic.class ); + List> methods2 = LuaMethod.GENERATOR.getMethods( Basic.class ); + assertThat( methods, sameInstance( methods2 ) ); + } + + @Test + public void testIdenticalMethods() + { + List> methods = LuaMethod.GENERATOR.getMethods( Basic.class ); + List> methods2 = LuaMethod.GENERATOR.getMethods( Basic2.class ); + assertThat( methods, contains( named( "go" ) ) ); + assertThat( methods.get( 0 ).getMethod(), sameInstance( methods2.get( 0 ).getMethod() ) ); + } + + @Test + public void testEmptyClass() + { + assertThat( LuaMethod.GENERATOR.getMethods( Empty.class ), is( empty() ) ); + } + + @Test + public void testNonPublicClass() + { + assertThat( LuaMethod.GENERATOR.getMethods( NonPublic.class ), is( empty() ) ); + } + + @Test + public void testNonInstance() + { + assertThat( LuaMethod.GENERATOR.getMethods( NonInstance.class ), is( empty() ) ); + } + + @Test + public void testIllegalThrows() + { + assertThat( LuaMethod.GENERATOR.getMethods( IllegalThrows.class ), is( empty() ) ); + } + + @Test + public void testCustomNames() + { + List> methods = LuaMethod.GENERATOR.getMethods( CustomNames.class ); + assertThat( methods, contains( named( "go1" ), named( "go2" ) ) ); + } + + @Test + public void testArgKinds() + { + List> methods = LuaMethod.GENERATOR.getMethods( ArgKinds.class ); + assertThat( methods, containsInAnyOrder( + named( "objectArg" ), named( "intArg" ), named( "optIntArg" ), + named( "context" ), named( "arguments" ) + ) ); + } + + @Test + public void testEnum() throws LuaException + { + List> methods = LuaMethod.GENERATOR.getMethods( EnumMethods.class ); + assertThat( methods, containsInAnyOrder( named( "getEnum" ), named( "optEnum" ) ) ); + + assertThat( apply( methods, new EnumMethods(), "getEnum", "front" ), one( is( "FRONT" ) ) ); + assertThat( apply( methods, new EnumMethods(), "optEnum", "front" ), one( is( "FRONT" ) ) ); + assertThat( apply( methods, new EnumMethods(), "optEnum" ), one( is( "?" ) ) ); + assertThrows( LuaException.class, () -> apply( methods, new EnumMethods(), "getEnum", "not as side" ) ); + } + + @Test + public void testMainThread() throws LuaException + { + List> methods = LuaMethod.GENERATOR.getMethods( MainThread.class ); + assertThat( methods, contains( allOf( + named( "go" ), + contramap( is( false ), "non-yielding", NamedMethod::nonYielding ) + ) ) ); + + assertThat( apply( methods, new MainThread(), "go" ), + contramap( notNullValue(), "callback", MethodResult::getCallback ) ); + } + + @Test + public void testUnsafe() + { + List> methods = LuaMethod.GENERATOR.getMethods( Unsafe.class ); + assertThat( methods, contains( named( "withUnsafe" ) ) ); + } + + public static class Basic + { + @LuaFunction + public final void go() + {} + } + + public static class Basic2 extends Basic + { + } + + public static class Empty + { + } + + static class NonPublic + { + @LuaFunction + public final void go() + {} + } + + public static class NonInstance + { + @LuaFunction + public static void go() + {} + } + + public static class IllegalThrows + { + @LuaFunction + public final void go() throws IOException + { + throw new IOException(); + } + } + + public static class CustomNames + { + @LuaFunction( { "go1", "go2" } ) + public final void go() + {} + } + + public static class ArgKinds + { + @LuaFunction + public final void objectArg( Object arg ) + {} + + @LuaFunction + public final void intArg( int arg ) + {} + + @LuaFunction + public final void optIntArg( Optional arg ) + {} + + @LuaFunction + public final void context( ILuaContext arg ) + {} + + @LuaFunction + public final void arguments( IArguments arg ) + {} + + @LuaFunction + public final void unknown( IComputerAccess arg ) + {} + + @LuaFunction + public final void illegalMap( Map arg ) + {} + + @LuaFunction + public final void optIllegalMap( Optional> arg ) + {} + } + + public static class EnumMethods + { + @LuaFunction + public final String getEnum( ComputerSide side ) + { + return side.name(); + } + + @LuaFunction + public final String optEnum( Optional side ) + { + return side.map( ComputerSide::name ).orElse( "?" ); + } + } + + public static class MainThread + { + @LuaFunction( mainThread = true ) + public final void go() + {} + } + + public static class Unsafe + { + @LuaFunction( unsafe = true ) + public final void withUnsafe( LuaTable table ) + {} + + @LuaFunction + public final void withoutUnsafe( LuaTable table ) + {} + + @LuaFunction( unsafe = true, mainThread = true ) + public final void invalid( LuaTable table ) + {} + } + + private static T find( Collection> methods, String name ) + { + return methods.stream() + .filter( x -> x.getName().equals( name ) ) + .map( NamedMethod::getMethod ) + .findAny() + .orElseThrow( NullPointerException::new ); + } + + public static MethodResult apply( Collection> methods, Object instance, String name, Object... args ) throws LuaException + { + return find( methods, name ).apply( instance, CONTEXT, new ObjectArguments( args ) ); + } + + public static Matcher one( Matcher object ) + { + return allOf( + contramap( nullValue(), "callback", MethodResult::getCallback ), + contramap( array( object ), "result", MethodResult::getResult ) + ); + } + + public static Matcher> named( String method ) + { + return contramap( is( method ), "name", NamedMethod::getName ); + } + + private static final ILuaContext CONTEXT = new ILuaContext() + { + @Override + public long issueMainThreadTask( @Nonnull ILuaTask task ) + { + return 0; + } + }; +} diff --git a/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java b/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java new file mode 100644 index 000000000..eeded8a31 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java @@ -0,0 +1,26 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.asm; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class IntCacheTest +{ + @Test + public void testCache() + { + IntCache c = new IntCache<>( i -> new Object() ); + assertEquals( c.get( 0 ), c.get( 0 ) ); + } + + @Test + public void testMassive() + { + assertEquals( 40, new IntCache<>( i -> i ).get( 40 ) ); + } +} diff --git a/src/test/java/dan200/computercraft/core/asm/MethodTest.java b/src/test/java/dan200/computercraft/core/asm/MethodTest.java new file mode 100644 index 000000000..fae4ae712 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/asm/MethodTest.java @@ -0,0 +1,264 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.asm; + +import dan200.computercraft.api.lua.*; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IDynamicPeripheral; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.computer.ComputerBootstrap; +import dan200.computercraft.core.computer.ComputerSide; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collections; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class MethodTest +{ + @Test + public void testMainThread() + { + ComputerBootstrap.run( "assert(main_thread.go() == 123)", x -> x.addApi( new MainThread() ), 50 ); + } + + @Test + public void testMainThreadPeripheral() + { + ComputerBootstrap.run( "assert(peripheral.call('top', 'go') == 123)", + x -> x.getEnvironment().setPeripheral( ComputerSide.TOP, new MainThread() ), + 50 ); + } + + @Test + public void testDynamic() + { + ComputerBootstrap.run( + "assert(dynamic.foo() == 123, 'foo: ' .. tostring(dynamic.foo()))\n" + + "assert(dynamic.bar() == 321, 'bar: ' .. tostring(dynamic.bar()))", + x -> x.addApi( new Dynamic() ), 50 ); + } + + @Test + public void testDynamicPeripheral() + { + ComputerBootstrap.run( + "local dynamic = peripheral.wrap('top')\n" + + "assert(dynamic.foo() == 123, 'foo: ' .. tostring(dynamic.foo()))\n" + + "assert(dynamic.bar() == 321, 'bar: ' .. tostring(dynamic.bar()))", + x -> x.getEnvironment().setPeripheral( ComputerSide.TOP, new Dynamic() ), + 50 + ); + } + + @Test + public void testExtra() + { + ComputerBootstrap.run( "assert(extra.go, 'go')\nassert(extra.go2, 'go2')", + x -> x.addApi( new ExtraObject() ), + 50 ); + } + + @Test + public void testPeripheralThrow() + { + ComputerBootstrap.run( + "local throw = peripheral.wrap('top')\n" + + "local _, err = pcall(throw.thisThread) assert(err == 'pcall: !', err)\n" + + "local _, err = pcall(throw.mainThread) assert(err == 'pcall: !', err)", + x -> x.getEnvironment().setPeripheral( ComputerSide.TOP, new PeripheralThrow() ), + 50 + ); + } + + @Test + public void testMany() + { + ComputerBootstrap.run( + "assert(many.method_0)\n" + + "assert(many.method_39)", + x -> x.addApi( new ManyMethods() ), 50 ); + } + + @Test + public void testFunction() + { + ComputerBootstrap.run( + "assert(func.call()(123) == 123)", + x -> x.addApi( new ReturnFunction() ), 50 ); + } + + public static class MainThread implements ILuaAPI, IPeripheral + { + public final String thread = Thread.currentThread().getName(); + + @Override + public String[] getNames() + { + return new String[] { "main_thread" }; + } + + @LuaFunction( mainThread = true ) + public final int go() + { + assertThat( Thread.currentThread().getName(), is( thread ) ); + return 123; + } + + @Nonnull + @Override + public String getType() + { + return "main_thread"; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } + + public static class Dynamic implements IDynamicLuaObject, ILuaAPI, IDynamicPeripheral + { + @Nonnull + @Override + public String[] getMethodNames() + { + return new String[] { "foo" }; + } + + @Nonnull + @Override + public MethodResult callMethod( @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) + { + return MethodResult.of( 123 ); + } + + @Nonnull + @Override + public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) + { + return callMethod( context, method, arguments ); + } + + @LuaFunction + public final int bar() + { + return 321; + } + + @Override + public String[] getNames() + { + return new String[] { "dynamic" }; + } + + @Nonnull + @Override + public String getType() + { + return "dynamic"; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } + + public static class ExtraObject implements ObjectSource, ILuaAPI + { + @Override + public String[] getNames() + { + return new String[] { "extra" }; + } + + @LuaFunction + public final void go2() + { + } + + @Override + public Iterable getExtra() + { + return Collections.singletonList( new GeneratorTest.Basic() ); + } + } + + public static class PeripheralThrow implements IPeripheral + { + @LuaFunction + public final void thisThread() throws LuaException + { + throw new LuaException( "!" ); + } + + @LuaFunction( mainThread = true ) + public final void mainThread() throws LuaException + { + throw new LuaException( "!" ); + } + + @Nonnull + @Override + public String getType() + { + return "throw"; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } + + public static class ManyMethods implements IDynamicLuaObject, ILuaAPI + { + @Nonnull + @Override + public String[] getMethodNames() + { + String[] methods = new String[40]; + for( int i = 0; i < methods.length; i++ ) methods[i] = "method_" + i; + return methods; + } + + @Nonnull + @Override + public MethodResult callMethod( @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) throws LuaException + { + return MethodResult.of(); + } + + @Override + public String[] getNames() + { + return new String[] { "many" }; + } + } + + public static class ReturnFunction implements ILuaAPI + { + @LuaFunction + public final ILuaFunction call() + { + return args -> MethodResult.of( args.getAll() ); + } + + @Override + public String[] getNames() + { + return new String[] { "func" }; + } + } +} diff --git a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java new file mode 100644 index 000000000..ea4734e26 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java @@ -0,0 +1,165 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.computer; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.core.filesystem.FileMount; +import dan200.computercraft.core.filesystem.JarMount; +import dan200.computercraft.core.filesystem.MemoryMount; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; + +/** + * A very basic environment. + */ +public class BasicEnvironment implements IComputerEnvironment +{ + private final IWritableMount mount; + + public BasicEnvironment() + { + this( new MemoryMount() ); + } + + public BasicEnvironment( IWritableMount mount ) + { + this.mount = mount; + } + + @Override + public int assignNewID() + { + return 0; + } + + @Override + public IWritableMount createSaveDirMount( String path, long space ) + { + return mount; + } + + @Override + public int getDay() + { + return 0; + } + + @Override + public double getTimeOfDay() + { + return 0; + } + + @Override + public boolean isColour() + { + return true; + } + + @Override + public long getComputerSpaceLimit() + { + return ComputerCraft.computerSpaceLimit; + } + + @Nonnull + @Override + public String getHostString() + { + return "ComputerCraft 1.0 (Test environment)"; + } + + @Nonnull + @Override + public String getUserAgent() + { + return "ComputerCraft/1.0"; + } + + @Override + public IMount createResourceMount( String domain, String subPath ) + { + return createMount( ComputerCraft.class, "data/" + domain + "/" + subPath, "main" ); + } + + @Override + public InputStream createResourceFile( String domain, String subPath ) + { + return ComputerCraft.class.getClassLoader().getResourceAsStream( "data/" + domain + "/" + subPath ); + } + + public static IMount createMount( Class klass, String path, String fallback ) + { + File file = getContainingFile( klass ); + + if( file.isFile() ) + { + try + { + return new JarMount( file, path ); + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + } + else + { + File wholeFile = new File( file, path ); + + // If we don't exist, walk up the tree looking for resource folders + File baseFile = file; + while( baseFile != null && !wholeFile.exists() ) + { + baseFile = baseFile.getParentFile(); + wholeFile = new File( baseFile, "src/" + fallback + "/resources/" + path ); + } + + if( !wholeFile.exists() ) throw new IllegalStateException( "Cannot find ROM mount at " + file ); + + return new FileMount( wholeFile, 0 ); + } + } + + + private static File getContainingFile( Class klass ) + { + String path = klass.getProtectionDomain().getCodeSource().getLocation().getPath(); + int bangIndex = path.indexOf( "!" ); + + // Plain old file, so step up from dan200.computercraft. + if( bangIndex < 0 ) return new File( path ); + + path = path.substring( 0, bangIndex ); + URL url; + try + { + url = new URL( path ); + } + catch( MalformedURLException e ) + { + throw new IllegalStateException( e ); + } + + try + { + return new File( url.toURI() ); + } + catch( URISyntaxException e ) + { + return new File( url.getPath() ); + } + } +} diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java new file mode 100644 index 000000000..e22e5dad8 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -0,0 +1,138 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.computer; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.ILuaAPI; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.core.filesystem.MemoryMount; +import dan200.computercraft.core.terminal.Terminal; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.function.Consumer; + +/** + * Helper class to run a program on a computer. + */ +public class ComputerBootstrap +{ + private static final int TPS = 20; + public static final int MAX_TIME = 10; + + public static void run( String program, Consumer setup, int maxTimes ) + { + MemoryMount mount = new MemoryMount() + .addFile( "test.lua", program ) + .addFile( "startup.lua", "assertion.assert(pcall(loadfile('test.lua', nil, _ENV))) os.shutdown()" ); + + run( mount, setup, maxTimes ); + } + + public static void run( String program, int maxTimes ) + { + run( program, x -> { }, maxTimes ); + } + + public static void run( IWritableMount mount, Consumer setup, int maxTicks ) + { + ComputerCraft.logComputerErrors = true; + ComputerCraft.maxMainComputerTime = ComputerCraft.maxMainGlobalTime = Integer.MAX_VALUE; + + Terminal term = new Terminal( ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); + final Computer computer = new Computer( new BasicEnvironment( mount ), term, 0 ); + + AssertApi api = new AssertApi(); + computer.addApi( api ); + + setup.accept( computer ); + + try + { + computer.turnOn(); + boolean everOn = false; + + for( int tick = 0; tick < TPS * maxTicks; tick++ ) + { + long start = System.currentTimeMillis(); + + computer.tick(); + MainThread.executePendingTasks(); + + if( api.message != null ) + { + ComputerCraft.log.debug( "Shutting down due to error" ); + computer.shutdown(); + Assertions.fail( api.message ); + return; + } + + long remaining = (1000 / TPS) - (System.currentTimeMillis() - start); + if( remaining > 0 ) Thread.sleep( remaining ); + + // Break if the computer was once on, and is now off. + everOn |= computer.isOn(); + if( (everOn || tick > TPS) && !computer.isOn() ) break; + } + + if( computer.isOn() || !api.didAssert ) + { + StringBuilder builder = new StringBuilder().append( "Did not correctly [" ); + if( !api.didAssert ) builder.append( " assert" ); + if( computer.isOn() ) builder.append( " shutdown" ); + builder.append( " ]\n" ); + + for( int line = 0; line < 19; line++ ) + { + builder.append( String.format( "%2d | %" + term.getWidth() + "s |\n", line + 1, term.getLine( line ) ) ); + } + + computer.shutdown(); + Assertions.fail( builder.toString() ); + } + } + catch( InterruptedException ignored ) + { + Thread.currentThread().interrupt(); + } + } + + public static class AssertApi implements ILuaAPI + { + boolean didAssert; + String message; + + @Override + public String[] getNames() + { + return new String[] { "assertion" }; + } + + @LuaFunction + public final void log( IArguments arguments ) + { + ComputerCraft.log.info( "[Computer] {}", Arrays.toString( arguments.getAll() ) ); + } + + @LuaFunction( "assert" ) + public final Object[] doAssert( IArguments arguments ) throws LuaException + { + didAssert = true; + + Object arg = arguments.get( 0 ); + if( arg == null || arg == Boolean.FALSE ) + { + message = arguments.optString( 1, "Assertion failed" ); + throw new LuaException( message ); + } + + return arguments.getAll(); + } + } +} diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerTest.java b/src/test/java/dan200/computercraft/core/computer/ComputerTest.java new file mode 100644 index 000000000..eee9c2303 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/computer/ComputerTest.java @@ -0,0 +1,49 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.computer; + +import com.google.common.io.CharStreams; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +import static java.time.Duration.ofSeconds; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; + +public class ComputerTest +{ + @Test + public void testTimeout() + { + assertTimeoutPreemptively( ofSeconds( 20 ), () -> { + try + { + ComputerBootstrap.run( "print('Hello') while true do end", ComputerBootstrap.MAX_TIME ); + } + catch( AssertionError e ) + { + if( e.getMessage().equals( "test.lua:1: Too long without yielding" ) ) return; + throw e; + } + + Assertions.fail( "Expected computer to timeout" ); + } ); + } + + public static void main( String[] args ) throws Exception + { + InputStream stream = ComputerTest.class.getClassLoader().getResourceAsStream( "benchmark.lua" ); + try( InputStreamReader reader = new InputStreamReader( Objects.requireNonNull( stream ), StandardCharsets.UTF_8 ) ) + { + String contents = CharStreams.toString( reader ); + ComputerBootstrap.run( contents, 1000 ); + } + } +} diff --git a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java new file mode 100644 index 000000000..a2a25ed14 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java @@ -0,0 +1,81 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.filesystem; + +import com.google.common.io.Files; +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.core.apis.ObjectWrapper; +import dan200.computercraft.core.apis.handles.EncodedWritableHandle; +import org.junit.jupiter.api.Test; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class FileSystemTest +{ + private static final File ROOT = new File( "test-files/filesystem" ); + private static final long CAPACITY = 1000000; + + private static FileSystem mkFs() throws FileSystemException + { + IWritableMount writableMount = new FileMount( ROOT, CAPACITY ); + return new FileSystem( "hdd", writableMount ); + + } + + /** + * Ensures writing a file truncates it. + * + * @throws FileSystemException When the file system cannot be constructed. + * @throws LuaException When Lua functions fail. + * @throws IOException When reading and writing from strings + */ + @Test + public void testWriteTruncates() throws FileSystemException, LuaException, IOException + { + FileSystem fs = mkFs(); + + { + FileSystemWrapper writer = fs.openForWrite( "out.txt", false, EncodedWritableHandle::openUtf8 ); + ObjectWrapper wrapper = new ObjectWrapper( new EncodedWritableHandle( writer.get(), writer ) ); + wrapper.call( "write", "This is a long line" ); + wrapper.call( "close" ); + } + + assertEquals( "This is a long line", Files.asCharSource( new File( ROOT, "out.txt" ), StandardCharsets.UTF_8 ).read() ); + + { + FileSystemWrapper writer = fs.openForWrite( "out.txt", false, EncodedWritableHandle::openUtf8 ); + ObjectWrapper wrapper = new ObjectWrapper( new EncodedWritableHandle( writer.get(), writer ) ); + wrapper.call( "write", "Tiny line" ); + wrapper.call( "close" ); + } + + assertEquals( "Tiny line", Files.asCharSource( new File( ROOT, "out.txt" ), StandardCharsets.UTF_8 ).read() ); + } + + @Test + public void testUnmountCloses() throws FileSystemException + { + FileSystem fs = mkFs(); + IWritableMount mount = new FileMount( new File( ROOT, "child" ), CAPACITY ); + fs.mountWritable( "disk", "disk", mount ); + + FileSystemWrapper writer = fs.openForWrite( "disk/out.txt", false, EncodedWritableHandle::openUtf8 ); + ObjectWrapper wrapper = new ObjectWrapper( new EncodedWritableHandle( writer.get(), writer ) ); + + fs.unmount( "disk" ); + + LuaException err = assertThrows( LuaException.class, () -> wrapper.call( "write", "Tiny line" ) ); + assertEquals( "attempt to use a closed file", err.getMessage() ); + } +} diff --git a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java new file mode 100644 index 000000000..c084065cd --- /dev/null +++ b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java @@ -0,0 +1,108 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.filesystem; + +import com.google.common.io.ByteStreams; +import dan200.computercraft.api.filesystem.IMount; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.*; + +public class JarMountTest +{ + private static final File ZIP_FILE = new File( "test-files/jar-mount.zip" ); + + private static final FileTime MODIFY_TIME = FileTime.from( Instant.EPOCH.plus( 2, ChronoUnit.DAYS ) ); + + @BeforeAll + public static void before() throws IOException + { + ZIP_FILE.getParentFile().mkdirs(); + + try( ZipOutputStream stream = new ZipOutputStream( new FileOutputStream( ZIP_FILE ) ) ) + { + stream.putNextEntry( new ZipEntry( "dir/" ) ); + stream.closeEntry(); + + stream.putNextEntry( new ZipEntry( "dir/file.lua" ).setLastModifiedTime( MODIFY_TIME ) ); + stream.write( "print('testing')".getBytes( StandardCharsets.UTF_8 ) ); + stream.closeEntry(); + } + } + + @Test + public void mountsDir() throws IOException + { + IMount mount = new JarMount( ZIP_FILE, "dir" ); + assertTrue( mount.isDirectory( "" ), "Root should be directory" ); + assertTrue( mount.exists( "file.lua" ), "File should exist" ); + } + + @Test + public void mountsFile() throws IOException + { + IMount mount = new JarMount( ZIP_FILE, "dir/file.lua" ); + assertTrue( mount.exists( "" ), "Root should exist" ); + assertFalse( mount.isDirectory( "" ), "Root should be a file" ); + } + + @Test + public void opensFileFromFile() throws IOException + { + IMount mount = new JarMount( ZIP_FILE, "dir/file.lua" ); + byte[] contents; + try( ReadableByteChannel stream = mount.openForRead( "" ) ) + { + contents = ByteStreams.toByteArray( Channels.newInputStream( stream ) ); + } + + assertEquals( new String( contents, StandardCharsets.UTF_8 ), "print('testing')" ); + } + + @Test + public void opensFileFromDir() throws IOException + { + IMount mount = new JarMount( ZIP_FILE, "dir" ); + byte[] contents; + try( ReadableByteChannel stream = mount.openForRead( "file.lua" ) ) + { + contents = ByteStreams.toByteArray( Channels.newInputStream( stream ) ); + } + + assertEquals( new String( contents, StandardCharsets.UTF_8 ), "print('testing')" ); + } + + @Test + public void fileAttributes() throws IOException + { + BasicFileAttributes attributes = new JarMount( ZIP_FILE, "dir" ).getAttributes( "file.lua" ); + assertFalse( attributes.isDirectory() ); + assertEquals( "print('testing')".length(), attributes.size() ); + assertEquals( MODIFY_TIME, attributes.lastModifiedTime() ); + } + + @Test + public void directoryAttributes() throws IOException + { + BasicFileAttributes attributes = new JarMount( ZIP_FILE, "dir" ).getAttributes( "" ); + assertTrue( attributes.isDirectory() ); + assertEquals( 0, attributes.size() ); + } +} diff --git a/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java new file mode 100644 index 000000000..dc785de3a --- /dev/null +++ b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java @@ -0,0 +1,148 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.filesystem; + +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.core.apis.handles.ArrayByteChannel; + +import javax.annotation.Nonnull; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.*; + +/** + * In-memory file mounts. + */ +public class MemoryMount implements IWritableMount +{ + private final Map files = new HashMap<>(); + private final Set directories = new HashSet<>(); + + public MemoryMount() + { + directories.add( "" ); + } + + + @Override + public void makeDirectory( @Nonnull String path ) + { + File file = new File( path ); + while( file != null ) + { + directories.add( file.getPath() ); + file = file.getParentFile(); + } + } + + @Override + public void delete( @Nonnull String path ) + { + if( files.containsKey( path ) ) + { + files.remove( path ); + } + else + { + directories.remove( path ); + for( String file : files.keySet().toArray( new String[0] ) ) + { + if( file.startsWith( path ) ) + { + files.remove( file ); + } + } + + File parent = new File( path ).getParentFile(); + if( parent != null ) delete( parent.getPath() ); + } + } + + @Nonnull + @Override + public WritableByteChannel openForWrite( @Nonnull final String path ) + { + return Channels.newChannel( new ByteArrayOutputStream() + { + @Override + public void close() throws IOException + { + super.close(); + files.put( path, toByteArray() ); + } + } ); + } + + @Nonnull + @Override + public WritableByteChannel openForAppend( @Nonnull final String path ) throws IOException + { + ByteArrayOutputStream stream = new ByteArrayOutputStream() + { + @Override + public void close() throws IOException + { + super.close(); + files.put( path, toByteArray() ); + } + }; + + byte[] current = files.get( path ); + if( current != null ) stream.write( current ); + + return Channels.newChannel( stream ); + } + + @Override + public long getRemainingSpace() + { + return 1000000L; + } + + @Override + public boolean exists( @Nonnull String path ) + { + return files.containsKey( path ) || directories.contains( path ); + } + + @Override + public boolean isDirectory( @Nonnull String path ) + { + return directories.contains( path ); + } + + @Override + public void list( @Nonnull String path, @Nonnull List files ) + { + for( String file : this.files.keySet() ) + { + if( file.startsWith( path ) ) files.add( file.substring( path.length() + 1 ) ); + } + } + + @Override + public long getSize( @Nonnull String path ) + { + throw new RuntimeException( "Not implemented" ); + } + + @Nonnull + @Override + public ReadableByteChannel openForRead( @Nonnull String path ) + { + return new ArrayByteChannel( files.get( path ) ); + } + + public MemoryMount addFile( String file, String contents ) + { + files.put( file, contents.getBytes() ); + return this; + } +} diff --git a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java new file mode 100644 index 000000000..daf93b599 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java @@ -0,0 +1,84 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.filesystem; + +import dan200.computercraft.api.filesystem.IMount; +import net.minecraft.Util; +import net.minecraft.server.packs.FolderPackResources; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.resources.ReloadableResourceManager; +import net.minecraft.util.Unit; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import static org.junit.jupiter.api.Assertions.*; + +public class ResourceMountTest +{ + private IMount mount; + + @BeforeEach + public void before() + { + ReloadableResourceManager manager = new ReloadableResourceManager( PackType.SERVER_DATA ); + CompletableFuture done = new CompletableFuture<>(); + manager.createReload( Util.backgroundExecutor(), Util.backgroundExecutor(), done, List.of( + new FolderPackResources( new File( "src/main/resources" ) ) + ) ); + + mount = ResourceMount.get( "computercraft", "lua/rom", manager ); + } + + @Test + public void testList() throws IOException + { + List files = new ArrayList<>(); + mount.list( "", files ); + files.sort( Comparator.naturalOrder() ); + + assertEquals( + Arrays.asList( "apis", "autorun", "help", "modules", "motd.txt", "programs", "startup.lua" ), + files + ); + } + + @Test + public void testExists() throws IOException + { + assertTrue( mount.exists( "" ) ); + assertTrue( mount.exists( "startup.lua" ) ); + assertTrue( mount.exists( "programs/fun/advanced/paint.lua" ) ); + + assertFalse( mount.exists( "programs/fun/advance/paint.lua" ) ); + assertFalse( mount.exists( "programs/fun/advanced/paint.lu" ) ); + } + + @Test + public void testIsDir() throws IOException + { + assertTrue( mount.isDirectory( "" ) ); + } + + @Test + public void testIsFile() throws IOException + { + assertFalse( mount.isDirectory( "startup.lua" ) ); + } + + @Test + public void testSize() throws IOException + { + assertNotEquals( mount.getSize( "startup.lua" ), 0 ); + } +} diff --git a/src/test/java/dan200/computercraft/core/terminal/TerminalMatchers.java b/src/test/java/dan200/computercraft/core/terminal/TerminalMatchers.java new file mode 100644 index 000000000..e72932472 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/terminal/TerminalMatchers.java @@ -0,0 +1,52 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.terminal; + +import dan200.computercraft.ContramapMatcher; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +import java.util.Arrays; + +public class TerminalMatchers +{ + public static Matcher textColourMatches( String[] x ) + { + return linesMatch( "text colour", Terminal::getTextColourLine, x ); + } + + public static Matcher backgroundColourMatches( String[] x ) + { + return linesMatch( "background colour", Terminal::getBackgroundColourLine, x ); + } + + public static Matcher textMatches( String[] x ) + { + return linesMatch( "text", Terminal::getLine, x ); + } + + @SuppressWarnings( "unchecked" ) + public static Matcher linesMatch( String kind, LineProvider getLine, String[] lines ) + { + return linesMatchWith( kind, getLine, Arrays.stream( lines ).map( Matchers::equalTo ).toArray( Matcher[]::new ) ); + } + + public static Matcher linesMatchWith( String kind, LineProvider getLine, Matcher[] lines ) + { + return new ContramapMatcher<>( kind, terminal -> { + String[] termLines = new String[terminal.getHeight()]; + for( int i = 0; i < termLines.length; i++ ) termLines[i] = getLine.getLine( terminal, i ).toString(); + return termLines; + }, Matchers.array( lines ) ); + } + + @FunctionalInterface + public interface LineProvider + { + TextBuffer getLine( Terminal terminal, int line ); + } + +} diff --git a/src/test/java/dan200/computercraft/core/terminal/TerminalTest.java b/src/test/java/dan200/computercraft/core/terminal/TerminalTest.java new file mode 100644 index 000000000..cc787b743 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/terminal/TerminalTest.java @@ -0,0 +1,717 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.terminal; + +import dan200.computercraft.shared.util.Colour; +import dan200.computercraft.utils.CallCounter; +import io.netty.buffer.Unpooled; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import org.hamcrest.Matcher; +import org.junit.jupiter.api.Test; + +import static dan200.computercraft.core.terminal.TerminalMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.junit.jupiter.api.Assertions.*; + +class TerminalTest +{ + @Test + void testCreation() + { + Terminal terminal = new Terminal( 16, 9 ); + assertEquals( 16, terminal.getWidth() ); + assertEquals( 9, terminal.getHeight() ); + } + + @Test + void testSetAndGetLine() + { + Terminal terminal = new Terminal( 16, 9 ); + terminal.setLine( 1, "ABCDEFGHIJKLMNOP", "0123456789abcdef", "fedcba9876543210" ); + assertEquals( "ABCDEFGHIJKLMNOP", terminal.getLine( 1 ).toString() ); + assertEquals( "0123456789abcdef", terminal.getTextColourLine( 1 ).toString() ); + assertEquals( "fedcba9876543210", terminal.getBackgroundColourLine( 1 ).toString() ); + } + + @Test + void testGetLineOutOfBounds() + { + Terminal terminal = new Terminal( 16, 9 ); + + assertNull( terminal.getLine( -5 ) ); + assertNull( terminal.getLine( 12 ) ); + + assertNull( terminal.getTextColourLine( -5 ) ); + assertNull( terminal.getTextColourLine( 12 ) ); + + assertNull( terminal.getBackgroundColourLine( -5 ) ); + assertNull( terminal.getBackgroundColourLine( 12 ) ); + } + + @Test + void testDefaults() + { + Terminal terminal = new Terminal( 16, 9 ); + assertEquals( 0, terminal.getCursorX() ); + assertEquals( 0, terminal.getCursorY() ); + assertFalse( terminal.getCursorBlink() ); + assertEquals( 0, terminal.getTextColour() ); + assertEquals( 15, terminal.getBackgroundColour() ); + } + + @Test + void testDefaultTextBuffer() + { + assertThat( new Terminal( 4, 3 ), textMatches( new String[] { + " ", + " ", + " ", + } ) ); + } + + @Test + void testDefaultTextColourBuffer() + { + assertThat( new Terminal( 4, 3 ), textColourMatches( new String[] { + "0000", + "0000", + "0000", + } ) ); + } + + @Test + void testDefaultBackgroundColourBuffer() + { + assertThat( new Terminal( 4, 3 ), TerminalMatchers.backgroundColourMatches( new String[] { + "ffff", + "ffff", + "ffff", + } ) ); + } + + @Test + void testZeroSizeBuffers() + { + String[] x = new String[0]; + assertThat( new Terminal( 0, 0 ), allOf( + textMatches( new String[0] ), + textColourMatches( x ), + TerminalMatchers.backgroundColourMatches( x ) + ) ); + } + + @Test + void testResizeWidthAndHeight() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + terminal.setLine( 0, "test", "aaaa", "eeee" ); + callCounter.reset(); + + terminal.resize( 5, 4 ); + + assertThat( terminal, allOf( + textMatches( new String[] { + "test ", + " ", + " ", + " ", + } ), + textColourMatches( new String[] { + "aaaa0", + "00000", + "00000", + "00000", + } ), TerminalMatchers.backgroundColourMatches( new String[] { + "eeeef", + "fffff", + "fffff", + "fffff", + } ) + ) ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testResizeSmaller() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + terminal.setLine( 0, "test", "aaaa", "eeee" ); + terminal.setLine( 1, "smol", "aaaa", "eeee" ); + terminal.setLine( 2, "term", "aaaa", "eeee" ); + callCounter.reset(); + + terminal.resize( 2, 2 ); + + assertThat( terminal, allOf( + textMatches( new String[] { + "te", + "sm", + } ), + textColourMatches( new String[] { + "aa", + "aa", + } ), + TerminalMatchers.backgroundColourMatches( new String[] { + "ee", + "ee", + } ) + ) ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testResizeWithSameDimensions() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + TerminalBufferSnapshot old = new TerminalBufferSnapshot( terminal ); + terminal.resize( 4, 3 ); + + assertThat( "Terminal should be unchanged", terminal, old.matches() ); + + callCounter.assertNotCalled(); + } + + @Test + void testSetAndGetCursorPos() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setCursorPos( 2, 1 ); + + assertEquals( 2, terminal.getCursorX() ); + assertEquals( 1, terminal.getCursorY() ); + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testSetCursorPosUnchanged() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setCursorPos( 2, 1 ); + callCounter.reset(); + terminal.setCursorPos( 2, 1 ); + + assertEquals( 2, terminal.getCursorX() ); + assertEquals( 1, terminal.getCursorY() ); + callCounter.assertNotCalled(); + } + + @Test + void testSetCursorBlink() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setCursorBlink( true ); + + assertTrue( terminal.getCursorBlink() ); + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testSetCursorBlinkUnchanged() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setCursorBlink( true ); + callCounter.reset(); + terminal.setCursorBlink( true ); + + assertTrue( terminal.getCursorBlink() ); + callCounter.assertNotCalled(); + } + + @Test + void testSetTextColour() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setTextColour( 5 ); + + assertEquals( terminal.getTextColour(), 5 ); + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testSetTextColourUnchanged() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setTextColour( 5 ); + callCounter.reset(); + terminal.setTextColour( 5 ); + + assertEquals( terminal.getTextColour(), 5 ); + callCounter.assertNotCalled(); + } + + @Test + void testSetBackgroundColour() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setBackgroundColour( 5 ); + + assertEquals( terminal.getBackgroundColour(), 5 ); + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testSetBackgroundColourUnchanged() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setBackgroundColour( 5 ); + callCounter.reset(); + terminal.setBackgroundColour( 5 ); + + assertEquals( terminal.getBackgroundColour(), 5 ); + callCounter.assertNotCalled(); + } + + @Test + void testBlitFromOrigin() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.blit( "test", "1234", "abcd" ); + + assertThat( terminal, allOf( + textMatches( new String[] { + "test", + " ", + " ", + } ), textColourMatches( new String[] { + "1234", + "0000", + "0000", + } ), backgroundColourMatches( new String[] { + "abcd", + "ffff", + "ffff", + } ) + ) ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testBlitWithOffset() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setCursorPos( 2, 1 ); + callCounter.reset(); + terminal.blit( "hi", "11", "ee" ); + + assertThat( terminal, allOf( + textMatches( new String[] { + " ", + " hi", + " ", + } ), + textColourMatches( new String[] { + "0000", + "0011", + "0000", + } ), + backgroundColourMatches( new String[] { + "ffff", + "ffee", + "ffff", + } ) + ) ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testBlitOutOfBounds() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + TerminalBufferSnapshot old = new TerminalBufferSnapshot( terminal ); + + terminal.setCursorPos( 2, -5 ); + callCounter.reset(); + terminal.blit( "hi", "11", "ee" ); + assertThat( terminal, old.matches() ); + callCounter.assertNotCalled(); + + terminal.setCursorPos( 2, 5 ); + callCounter.reset(); + terminal.blit( "hi", "11", "ee" ); + assertThat( terminal, old.matches() ); + callCounter.assertNotCalled(); + } + + @Test + void testWriteFromOrigin() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.write( "test" ); + + assertThat( terminal, allOf( + textMatches( new String[] { + "test", + " ", + " ", + } ), textColourMatches( new String[] { + "0000", + "0000", + "0000", + } ), backgroundColourMatches( new String[] { + "ffff", + "ffff", + "ffff", + } ) + ) ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testWriteWithOffset() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setCursorPos( 2, 1 ); + callCounter.reset(); + terminal.write( "hi" ); + + assertThat( terminal, allOf( + textMatches( new String[] { + " ", + " hi", + " ", + } ), + textColourMatches( new String[] { + "0000", + "0000", + "0000", + } ), + backgroundColourMatches( new String[] { + "ffff", + "ffff", + "ffff", + } ) + ) ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testWriteOutOfBounds() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + TerminalBufferSnapshot old = new TerminalBufferSnapshot( terminal ); + + terminal.setCursorPos( 2, -5 ); + callCounter.reset(); + terminal.write( "hi" ); + + assertThat( terminal, old.matches() ); + callCounter.assertNotCalled(); + + terminal.setCursorPos( 2, 5 ); + callCounter.reset(); + terminal.write( "hi" ); + assertThat( terminal, old.matches() ); + callCounter.assertNotCalled(); + } + + @Test + void testScrollUp() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setLine( 1, "test", "1111", "eeee" ); + callCounter.reset(); + terminal.scroll( 1 ); + + assertThat( terminal, allOf( + textMatches( new String[] { + "test", + " ", + " ", + } ), + textColourMatches( new String[] { + "1111", + "0000", + "0000", + } ), + backgroundColourMatches( new String[] { + "eeee", + "ffff", + "ffff", + } ) + ) ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testScrollDown() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setLine( 1, "test", "1111", "eeee" ); + callCounter.reset(); + terminal.scroll( -1 ); + + assertThat( terminal, allOf( + textMatches( new String[] { + " ", + " ", + "test", + } ), + textColourMatches( new String[] { + "0000", + "0000", + "1111", + } ), + backgroundColourMatches( new String[] { + "ffff", + "ffff", + "eeee", + } ) + ) ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testScrollZeroLinesUnchanged() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + + terminal.setLine( 1, "test", "1111", "eeee" ); + TerminalBufferSnapshot old = new TerminalBufferSnapshot( terminal ); + callCounter.reset(); + terminal.scroll( 0 ); + + assertThat( terminal, old.matches() ); + + callCounter.assertNotCalled(); + } + + @Test + void testClear() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + TerminalBufferSnapshot old = new TerminalBufferSnapshot( terminal ); + + terminal.setLine( 1, "test", "1111", "eeee" ); + callCounter.reset(); + terminal.clear(); + + assertThat( terminal, old.matches() ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testClearLine() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + TerminalBufferSnapshot old = new TerminalBufferSnapshot( terminal ); + + terminal.setLine( 1, "test", "1111", "eeee" ); + terminal.setCursorPos( 0, 1 ); + callCounter.reset(); + terminal.clearLine(); + + assertThat( terminal, old.matches() ); + + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testClearLineOutOfBounds() + { + CallCounter callCounter = new CallCounter(); + Terminal terminal = new Terminal( 4, 3, callCounter ); + TerminalBufferSnapshot old; + + terminal.setLine( 1, "test", "1111", "eeee" ); + old = new TerminalBufferSnapshot( terminal ); + terminal.setCursorPos( 0, -5 ); + callCounter.reset(); + terminal.clearLine(); + assertThat( terminal, old.matches() ); + callCounter.assertNotCalled(); + + terminal.setLine( 1, "test", "1111", "eeee" ); + old = new TerminalBufferSnapshot( terminal ); + terminal.setCursorPos( 0, 5 ); + callCounter.reset(); + terminal.clearLine(); + assertThat( terminal, old.matches() ); + callCounter.assertNotCalled(); + } + + @Test + void testPacketBufferRoundtrip() + { + Terminal writeTerminal = new Terminal( 2, 1 ); + + writeTerminal.blit( "hi", "11", "ee" ); + writeTerminal.setCursorPos( 2, 5 ); + writeTerminal.setTextColour( 3 ); + writeTerminal.setBackgroundColour( 5 ); + + FriendlyByteBuf packetBuffer = new FriendlyByteBuf( Unpooled.buffer() ); + writeTerminal.write( packetBuffer ); + + CallCounter callCounter = new CallCounter(); + Terminal readTerminal = new Terminal( 2, 1, callCounter ); + packetBuffer.writeBytes( packetBuffer ); + readTerminal.read( packetBuffer ); + + assertThat( readTerminal, allOf( + textMatches( new String[] { "hi", } ), + textColourMatches( new String[] { "11", } ), + backgroundColourMatches( new String[] { "ee", } ) + ) ); + + assertEquals( 2, readTerminal.getCursorX() ); + assertEquals( 5, readTerminal.getCursorY() ); + assertEquals( 3, readTerminal.getTextColour() ); + assertEquals( 5, readTerminal.getBackgroundColour() ); + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testNbtRoundtrip() + { + Terminal writeTerminal = new Terminal( 10, 5 ); + writeTerminal.blit( "hi", "11", "ee" ); + writeTerminal.setCursorPos( 2, 5 ); + writeTerminal.setTextColour( 3 ); + writeTerminal.setBackgroundColour( 5 ); + + CompoundTag nbt = new CompoundTag(); + writeTerminal.writeToNBT( nbt ); + + CallCounter callCounter = new CallCounter(); + Terminal readTerminal = new Terminal( 2, 1, callCounter ); + + readTerminal.readFromNBT( nbt ); + + assertThat( readTerminal, allOf( + textMatches( new String[] { "hi", } ), + textColourMatches( new String[] { "11", } ), + backgroundColourMatches( new String[] { "ee", } ) + ) ); + + assertEquals( 2, readTerminal.getCursorX() ); + assertEquals( 5, readTerminal.getCursorY() ); + assertEquals( 3, readTerminal.getTextColour() ); + assertEquals( 5, readTerminal.getBackgroundColour() ); + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testReadWriteNBTEmpty() + { + Terminal terminal = new Terminal( 0, 0 ); + + CompoundTag nbt = new CompoundTag(); + terminal.writeToNBT( nbt ); + + CallCounter callCounter = new CallCounter(); + terminal = new Terminal( 0, 1, callCounter ); + terminal.readFromNBT( nbt ); + + assertThat( terminal, allOf( + textMatches( new String[] { "", } ), + textColourMatches( new String[] { "", } ), + backgroundColourMatches( new String[] { "", } ) + ) ); + + assertEquals( 0, terminal.getCursorX() ); + assertEquals( 0, terminal.getCursorY() ); + assertEquals( 0, terminal.getTextColour() ); + assertEquals( 15, terminal.getBackgroundColour() ); + callCounter.assertCalledTimes( 1 ); + } + + @Test + void testGetColour() + { + // 0 - 9 + assertEquals( 0, Terminal.getColour( '0', Colour.WHITE ) ); + assertEquals( 1, Terminal.getColour( '1', Colour.WHITE ) ); + assertEquals( 8, Terminal.getColour( '8', Colour.WHITE ) ); + assertEquals( 9, Terminal.getColour( '9', Colour.WHITE ) ); + + // a - f + assertEquals( 10, Terminal.getColour( 'a', Colour.WHITE ) ); + assertEquals( 11, Terminal.getColour( 'b', Colour.WHITE ) ); + assertEquals( 14, Terminal.getColour( 'e', Colour.WHITE ) ); + assertEquals( 15, Terminal.getColour( 'f', Colour.WHITE ) ); + + // char out of bounds -> use colour enum ordinal + assertEquals( 0, Terminal.getColour( 'z', Colour.WHITE ) ); + assertEquals( 0, Terminal.getColour( '!', Colour.WHITE ) ); + assertEquals( 0, Terminal.getColour( 'Z', Colour.WHITE ) ); + assertEquals( 5, Terminal.getColour( 'Z', Colour.LIME ) ); + } + + private static final class TerminalBufferSnapshot + { + final String[] textLines; + final String[] textColourLines; + final String[] backgroundColourLines; + + private TerminalBufferSnapshot( Terminal terminal ) + { + textLines = new String[terminal.getHeight()]; + textColourLines = new String[terminal.getHeight()]; + backgroundColourLines = new String[terminal.getHeight()]; + + for( int i = 0; i < terminal.getHeight(); i++ ) + { + textLines[i] = terminal.getLine( i ).toString(); + textColourLines[i] = terminal.getTextColourLine( i ).toString(); + backgroundColourLines[i] = terminal.getBackgroundColourLine( i ).toString(); + } + } + + public Matcher matches() + { + return allOf( + textMatches( textLines ), textColourMatches( textColourLines ), TerminalMatchers.backgroundColourMatches( backgroundColourLines ) + ); + } + } +} diff --git a/src/test/java/dan200/computercraft/core/terminal/TextBufferTest.java b/src/test/java/dan200/computercraft/core/terminal/TextBufferTest.java new file mode 100644 index 000000000..e5544ccdc --- /dev/null +++ b/src/test/java/dan200/computercraft/core/terminal/TextBufferTest.java @@ -0,0 +1,150 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.terminal; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class TextBufferTest +{ + @Test + void testStringConstructor() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + assertEquals( "test", textBuffer.toString() ); + } + + @Test + void testCharRepetitionConstructor() + { + TextBuffer textBuffer = new TextBuffer( 'a', 5 ); + assertEquals( "aaaaa", textBuffer.toString() ); + } + + @Test + void testLength() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + assertEquals( 4, textBuffer.length() ); + } + + @Test + void testWrite() + { + TextBuffer textBuffer = new TextBuffer( ' ', 4 ); + textBuffer.write( "test" ); + assertEquals( "test", textBuffer.toString() ); + } + + @Test + void testWriteTextBuffer() + { + TextBuffer source = new TextBuffer( "test" ); + TextBuffer target = new TextBuffer( " " ); + target.write( source ); + assertEquals( "test", target.toString() ); + } + + @Test + void testWriteFromPos() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.write( "il", 1 ); + assertEquals( "tilt", textBuffer.toString() ); + } + + @Test + void testWriteOutOfBounds() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.write( "abcdefghijklmnop", -5 ); + assertEquals( "fghi", textBuffer.toString() ); + } + + @Test + void testWriteOutOfBounds2() + { + TextBuffer textBuffer = new TextBuffer( " " ); + textBuffer.write( "Hello, world!", -3 ); + assertEquals( "lo, world! ", textBuffer.toString() ); + } + + @Test + void testFill() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.fill( 'c' ); + assertEquals( "cccc", textBuffer.toString() ); + } + + @Test + void testFillSubstring() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.fill( 'c', 1, 3 ); + assertEquals( "tcct", textBuffer.toString() ); + } + + @Test + void testFillOutOfBounds() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.fill( 'c', -5, 5 ); + assertEquals( "cccc", textBuffer.toString() ); + } + + @Test + void testCharAt() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + assertEquals( 'e', textBuffer.charAt( 1 ) ); + } + + @Test + void testSetChar() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.setChar( 2, 'n' ); + assertEquals( "tent", textBuffer.toString() ); + } + + @Test + void testSetCharWithNegativeIndex() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.setChar( -5, 'n' ); + assertEquals( "test", textBuffer.toString(), "Buffer should not change after setting char with negative index." ); + } + + @Test + void testSetCharWithIndexBeyondBufferEnd() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.setChar( 10, 'n' ); + assertEquals( "test", textBuffer.toString(), "Buffer should not change after setting char beyond buffer end." ); + } + + @Test + void testMultipleOperations() + { + TextBuffer textBuffer = new TextBuffer( ' ', 5 ); + textBuffer.setChar( 0, 'H' ); + textBuffer.setChar( 1, 'e' ); + textBuffer.setChar( 2, 'l' ); + textBuffer.write( "lo", 3 ); + assertEquals( "Hello", textBuffer.toString(), "TextBuffer failed to persist over multiple operations." ); + } + + @Test + void testEmptyBuffer() + { + TextBuffer textBuffer = new TextBuffer( "" ); + // exception on writing to empty buffer would fail the test + textBuffer.write( "test" ); + assertEquals( "", textBuffer.toString() ); + } +} diff --git a/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java b/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java new file mode 100644 index 000000000..ac99068f7 --- /dev/null +++ b/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java @@ -0,0 +1,84 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.network.client; + +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.terminal.TextBuffer; +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import org.junit.jupiter.api.RepeatedTest; + +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests {@link TerminalState} round tripping works as expected. + */ +public class TerminalStateTest +{ + @RepeatedTest( 5 ) + public void testCompressed() + { + Terminal terminal = randomTerminal(); + + FriendlyByteBuf buffer = new FriendlyByteBuf( Unpooled.directBuffer() ); + new TerminalState( true, terminal, true ).write( buffer ); + + checkEqual( terminal, read( buffer ) ); + assertEquals( 0, buffer.readableBytes() ); + } + + @RepeatedTest( 5 ) + public void testUncompressed() + { + Terminal terminal = randomTerminal(); + + FriendlyByteBuf buffer = new FriendlyByteBuf( Unpooled.directBuffer() ); + new TerminalState( true, terminal, false ).write( buffer ); + + checkEqual( terminal, read( buffer ) ); + assertEquals( 0, buffer.readableBytes() ); + } + + private static Terminal randomTerminal() + { + Random random = new Random(); + Terminal terminal = new Terminal( 10, 5 ); + for( int y = 0; y < terminal.getHeight(); y++ ) + { + TextBuffer buffer = terminal.getLine( y ); + for( int x = 0; x < buffer.length(); x++ ) buffer.setChar( x, (char) (random.nextInt( 26 ) + 65) ); + } + + return terminal; + } + + private static void checkEqual( Terminal expected, Terminal actual ) + { + assertNotNull( expected, "Expected cannot be null" ); + assertNotNull( actual, "Actual cannot be null" ); + assertEquals( expected.getHeight(), actual.getHeight(), "Heights must match" ); + assertEquals( expected.getWidth(), actual.getWidth(), "Widths must match" ); + + for( int y = 0; y < expected.getHeight(); y++ ) + { + assertEquals( expected.getLine( y ).toString(), actual.getLine( y ).toString() ); + } + } + + private static Terminal read( FriendlyByteBuf buffer ) + { + TerminalState state = new TerminalState( buffer ); + assertTrue( state.colour ); + + if( !state.hasTerminal() ) return null; + + Terminal other = new Terminal( state.width, state.height ); + state.apply( other ); + return other; + } +} diff --git a/src/test/java/dan200/computercraft/shared/peripheral/speaker/DfpwmStateTest.java b/src/test/java/dan200/computercraft/shared/peripheral/speaker/DfpwmStateTest.java new file mode 100644 index 000000000..cc3325514 --- /dev/null +++ b/src/test/java/dan200/computercraft/shared/peripheral/speaker/DfpwmStateTest.java @@ -0,0 +1,39 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.peripheral.speaker; + +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.ObjectLuaTable; +import org.junit.jupiter.api.Test; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +class DfpwmStateTest +{ + @Test + public void testEncoder() throws LuaException + { + int[] input = new int[] { 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -6, -6, -6, -7, -7, -7, -7, -7, -7, -7, -7, -7, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -5, -5, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -7, -7, -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3 }; + Map inputTbl = new HashMap<>(); + for( int i = 0; i < input.length; i++ ) inputTbl.put( (double) (i + 1), input[i] ); + + DfpwmState state = new DfpwmState(); + state.pushBuffer( new ObjectLuaTable( inputTbl ), input.length, Optional.empty() ); + ByteBuffer result = state.pullPending( 0 ); + byte[] contents = new byte[result.remaining()]; + result.get( contents ); + + assertArrayEquals( + new byte[] { 87, 74, 42, -91, -92, -108, 84, -87, -86, 86, -83, 90, -83, -43, 90, -85, -42, 106, -43, -86, 106, -107, 42, -107, 74, -87, 74, -91, 74, -91, -86, -86, 106, 85, 107, -83, 106, -83, -83, 86, -75, -86, 42, 85, -107, 82, 41, -91, 82, 74, 41, -107, -86, -44, -86, 86, -75, 106, -83, -75, -86, -75, 90, -83, -86, -86, -86, 82, -91, 74, -107, -86, 82, -87, 82, 85, 85, 85, -83, 86, -75, -86, -43, 90, -83, 90, 85, 85, -107, 42, -91, 82, -86, 82, 74, 41, 85, -87, -86, -86, 106, -75, 90, -83, 86, -85, 106, -43, 106, 85, 85, 85, 85, -107, 42, 85, -86, 42, -107, -86, -86, -86, -86, 106, -75, -86, 86, -85 }, + contents + ); + } +} diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java new file mode 100644 index 000000000..9d490b5d6 --- /dev/null +++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java @@ -0,0 +1,463 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.wired; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.network.wired.IWiredElement; +import dan200.computercraft.api.network.wired.IWiredNetwork; +import dan200.computercraft.api.network.wired.IWiredNetworkChange; +import dan200.computercraft.api.network.wired.IWiredNode; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.util.DirectionUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +import static org.junit.jupiter.api.Assertions.*; + +public class NetworkTest +{ + @Test + public void testConnect() + { + NetworkElement + aE = new NetworkElement( null, null, "a" ), + bE = new NetworkElement( null, null, "b" ), + cE = new NetworkElement( null, null, "c" ); + + IWiredNode + aN = aE.getNode(), + bN = bE.getNode(), + cN = cE.getNode(); + + assertNotEquals( aN.getNetwork(), bN.getNetwork(), "A's and B's network must be different" ); + assertNotEquals( aN.getNetwork(), cN.getNetwork(), "A's and C's network must be different" ); + assertNotEquals( bN.getNetwork(), cN.getNetwork(), "B's and C's network must be different" ); + + assertTrue( aN.getNetwork().connect( aN, bN ), "Must be able to add connection" ); + assertFalse( aN.getNetwork().connect( aN, bN ), "Cannot add connection twice" ); + + assertEquals( aN.getNetwork(), bN.getNetwork(), "A's and B's network must be equal" ); + assertEquals( Sets.newHashSet( aN, bN ), nodes( aN.getNetwork() ), "A's network should be A and B" ); + + assertEquals( Sets.newHashSet( "a", "b" ), aE.allPeripherals().keySet(), "A's peripheral set should be A, B" ); + assertEquals( Sets.newHashSet( "a", "b" ), bE.allPeripherals().keySet(), "B's peripheral set should be A, B" ); + + aN.getNetwork().connect( aN, cN ); + + assertEquals( aN.getNetwork(), bN.getNetwork(), "A's and B's network must be equal" ); + assertEquals( aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal" ); + assertEquals( Sets.newHashSet( aN, bN, cN ), nodes( aN.getNetwork() ), "A's network should be A, B and C" ); + + assertEquals( Sets.newHashSet( bN, cN ), neighbours( aN ), "A's neighbour set should be B, C" ); + assertEquals( Sets.newHashSet( aN ), neighbours( bN ), "B's neighbour set should be A" ); + assertEquals( Sets.newHashSet( aN ), neighbours( cN ), "C's neighbour set should be A" ); + + assertEquals( Sets.newHashSet( "a", "b", "c" ), aE.allPeripherals().keySet(), "A's peripheral set should be A, B, C" ); + assertEquals( Sets.newHashSet( "a", "b", "c" ), bE.allPeripherals().keySet(), "B's peripheral set should be A, B, C" ); + assertEquals( Sets.newHashSet( "a", "b", "c" ), cE.allPeripherals().keySet(), "C's peripheral set should be A, B, C" ); + } + + @Test + public void testDisconnectNoChange() + { + NetworkElement + aE = new NetworkElement( null, null, "a" ), + bE = new NetworkElement( null, null, "b" ), + cE = new NetworkElement( null, null, "c" ); + + IWiredNode + aN = aE.getNode(), + bN = bE.getNode(), + cN = cE.getNode(); + + aN.getNetwork().connect( aN, bN ); + aN.getNetwork().connect( aN, cN ); + aN.getNetwork().connect( bN, cN ); + + aN.getNetwork().disconnect( aN, bN ); + + assertEquals( aN.getNetwork(), bN.getNetwork(), "A's and B's network must be equal" ); + assertEquals( aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal" ); + assertEquals( Sets.newHashSet( aN, bN, cN ), nodes( aN.getNetwork() ), "A's network should be A, B and C" ); + + assertEquals( Sets.newHashSet( "a", "b", "c" ), aE.allPeripherals().keySet(), "A's peripheral set should be A, B, C" ); + assertEquals( Sets.newHashSet( "a", "b", "c" ), bE.allPeripherals().keySet(), "B's peripheral set should be A, B, C" ); + assertEquals( Sets.newHashSet( "a", "b", "c" ), cE.allPeripherals().keySet(), "C's peripheral set should be A, B, C" ); + } + + @Test + public void testDisconnectLeaf() + { + NetworkElement + aE = new NetworkElement( null, null, "a" ), + bE = new NetworkElement( null, null, "b" ), + cE = new NetworkElement( null, null, "c" ); + + IWiredNode + aN = aE.getNode(), + bN = bE.getNode(), + cN = cE.getNode(); + + aN.getNetwork().connect( aN, bN ); + aN.getNetwork().connect( aN, cN ); + + aN.getNetwork().disconnect( aN, bN ); + + assertNotEquals( aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal" ); + assertEquals( aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal" ); + assertEquals( Sets.newHashSet( aN, cN ), nodes( aN.getNetwork() ), "A's network should be A and C" ); + assertEquals( Sets.newHashSet( bN ), nodes( bN.getNetwork() ), "B's network should be B" ); + + assertEquals( Sets.newHashSet( "a", "c" ), aE.allPeripherals().keySet(), "A's peripheral set should be A, C" ); + assertEquals( Sets.newHashSet( "b" ), bE.allPeripherals().keySet(), "B's peripheral set should be B" ); + assertEquals( Sets.newHashSet( "a", "c" ), cE.allPeripherals().keySet(), "C's peripheral set should be A, C" ); + } + + @Test + public void testDisconnectSplit() + { + NetworkElement + aE = new NetworkElement( null, null, "a" ), + aaE = new NetworkElement( null, null, "a_" ), + bE = new NetworkElement( null, null, "b" ), + bbE = new NetworkElement( null, null, "b_" ); + + IWiredNode + aN = aE.getNode(), + aaN = aaE.getNode(), + bN = bE.getNode(), + bbN = bbE.getNode(); + + aN.getNetwork().connect( aN, aaN ); + bN.getNetwork().connect( bN, bbN ); + + aN.getNetwork().connect( aN, bN ); + + aN.getNetwork().disconnect( aN, bN ); + + assertNotEquals( aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal" ); + assertEquals( aN.getNetwork(), aaN.getNetwork(), "A's and A_'s network must be equal" ); + assertEquals( bN.getNetwork(), bbN.getNetwork(), "B's and B_'s network must be equal" ); + + assertEquals( Sets.newHashSet( aN, aaN ), nodes( aN.getNetwork() ), "A's network should be A and A_" ); + assertEquals( Sets.newHashSet( bN, bbN ), nodes( bN.getNetwork() ), "B's network should be B and B_" ); + + assertEquals( Sets.newHashSet( "a", "a_" ), aE.allPeripherals().keySet(), "A's peripheral set should be A and A_" ); + assertEquals( Sets.newHashSet( "b", "b_" ), bE.allPeripherals().keySet(), "B's peripheral set should be B and B_" ); + } + + @Test + public void testRemoveSingle() + { + NetworkElement aE = new NetworkElement( null, null, "a" ); + IWiredNode aN = aE.getNode(); + + IWiredNetwork network = aN.getNetwork(); + assertFalse( aN.remove(), "Cannot remove node from an empty network" ); + assertEquals( network, aN.getNetwork(), "Networks are same before and after" ); + } + + @Test + public void testRemoveLeaf() + { + NetworkElement + aE = new NetworkElement( null, null, "a" ), + bE = new NetworkElement( null, null, "b" ), + cE = new NetworkElement( null, null, "c" ); + + IWiredNode + aN = aE.getNode(), + bN = bE.getNode(), + cN = cE.getNode(); + + aN.getNetwork().connect( aN, bN ); + aN.getNetwork().connect( aN, cN ); + + assertTrue( aN.getNetwork().remove( bN ), "Must be able to remove node" ); + assertFalse( aN.getNetwork().remove( bN ), "Cannot remove a second time" ); + + assertNotEquals( aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal" ); + assertEquals( aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal" ); + + assertEquals( Sets.newHashSet( aN, cN ), nodes( aN.getNetwork() ), "A's network should be A and C" ); + assertEquals( Sets.newHashSet( bN ), nodes( bN.getNetwork() ), "B's network should be B" ); + + assertEquals( Sets.newHashSet( "a", "c" ), aE.allPeripherals().keySet(), "A's peripheral set should be A, C" ); + assertEquals( Sets.newHashSet(), bE.allPeripherals().keySet(), "B's peripheral set should be empty" ); + assertEquals( Sets.newHashSet( "a", "c" ), cE.allPeripherals().keySet(), "C's peripheral set should be A, C" ); + } + + @Test + public void testRemoveSplit() + { + NetworkElement + aE = new NetworkElement( null, null, "a" ), + aaE = new NetworkElement( null, null, "a_" ), + bE = new NetworkElement( null, null, "b" ), + bbE = new NetworkElement( null, null, "b_" ), + cE = new NetworkElement( null, null, "c" ); + + IWiredNode + aN = aE.getNode(), + aaN = aaE.getNode(), + bN = bE.getNode(), + bbN = bbE.getNode(), + cN = cE.getNode(); + + aN.getNetwork().connect( aN, aaN ); + bN.getNetwork().connect( bN, bbN ); + + cN.getNetwork().connect( aN, cN ); + cN.getNetwork().connect( bN, cN ); + + cN.getNetwork().remove( cN ); + + assertNotEquals( aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal" ); + assertEquals( aN.getNetwork(), aaN.getNetwork(), "A's and A_'s network must be equal" ); + assertEquals( bN.getNetwork(), bbN.getNetwork(), "B's and B_'s network must be equal" ); + + assertEquals( Sets.newHashSet( aN, aaN ), nodes( aN.getNetwork() ), "A's network should be A and A_" ); + assertEquals( Sets.newHashSet( bN, bbN ), nodes( bN.getNetwork() ), "B's network should be B and B_" ); + assertEquals( Sets.newHashSet( cN ), nodes( cN.getNetwork() ), "C's network should be C" ); + + assertEquals( Sets.newHashSet( "a", "a_" ), aE.allPeripherals().keySet(), "A's peripheral set should be A and A_" ); + assertEquals( Sets.newHashSet( "b", "b_" ), bE.allPeripherals().keySet(), "B's peripheral set should be B and B_" ); + assertEquals( Sets.newHashSet(), cE.allPeripherals().keySet(), "C's peripheral set should be empty" ); + } + + private static final int BRUTE_SIZE = 16; + private static final int TOGGLE_CONNECTION_TIMES = 5; + private static final int TOGGLE_NODE_TIMES = 5; + + @Test + @Disabled( "Takes a long time to run, mostly for stress testing" ) + public void testLarge() + { + Grid grid = new Grid<>( BRUTE_SIZE ); + grid.map( ( existing, pos ) -> new NetworkElement( null, null, "n_" + pos ).getNode() ); + + // Test connecting + { + long start = System.nanoTime(); + + grid.forEach( ( existing, pos ) -> { + for( Direction facing : DirectionUtil.FACINGS ) + { + BlockPos offset = pos.relative( facing ); + if( offset.getX() > BRUTE_SIZE / 2 == pos.getX() > BRUTE_SIZE / 2 ) + { + IWiredNode other = grid.get( offset ); + if( other != null ) existing.getNetwork().connect( existing, other ); + } + } + } ); + + long end = System.nanoTime(); + + System.out.printf( "Connecting %s³ nodes took %s seconds\n", BRUTE_SIZE, (end - start) * 1e-9 ); + } + + // Test toggling + { + IWiredNode left = grid.get( new BlockPos( BRUTE_SIZE / 2, 0, 0 ) ); + IWiredNode right = grid.get( new BlockPos( BRUTE_SIZE / 2 + 1, 0, 0 ) ); + assertNotEquals( left.getNetwork(), right.getNetwork() ); + + long start = System.nanoTime(); + for( int i = 0; i < TOGGLE_CONNECTION_TIMES; i++ ) + { + left.getNetwork().connect( left, right ); + left.getNetwork().disconnect( left, right ); + } + + long end = System.nanoTime(); + + System.out.printf( "Toggling connection %s times took %s seconds\n", TOGGLE_CONNECTION_TIMES, (end - start) * 1e-9 ); + } + + { + IWiredNode left = grid.get( new BlockPos( BRUTE_SIZE / 2, 0, 0 ) ); + IWiredNode right = grid.get( new BlockPos( BRUTE_SIZE / 2 + 1, 0, 0 ) ); + IWiredNode centre = new NetworkElement( null, null, "c" ).getNode(); + assertNotEquals( left.getNetwork(), right.getNetwork() ); + + long start = System.nanoTime(); + for( int i = 0; i < TOGGLE_NODE_TIMES; i++ ) + { + left.getNetwork().connect( left, centre ); + right.getNetwork().connect( right, centre ); + + left.getNetwork().remove( centre ); + } + + long end = System.nanoTime(); + + System.out.printf( "Toggling node %s times took %s seconds\n", TOGGLE_NODE_TIMES, (end - start) * 1e-9 ); + } + } + + private static final class NetworkElement implements IWiredElement + { + private final Level world; + private final Vec3 position; + private final String id; + private final IWiredNode node; + private final Map localPeripherals = Maps.newHashMap(); + private final Map remotePeripherals = Maps.newHashMap(); + + private NetworkElement( Level world, Vec3 position, String id ) + { + this.world = world; + this.position = position; + this.id = id; + this.node = ComputerCraftAPI.createWiredNodeForElement( this ); + this.addPeripheral( id ); + } + + @Nonnull + @Override + public Level getLevel() + { + return world; + } + + @Nonnull + @Override + public Vec3 getPosition() + { + return position; + } + + @Nonnull + @Override + public String getSenderID() + { + return id; + } + + @Override + public String toString() + { + return "NetworkElement{" + id + "}"; + } + + @Nonnull + @Override + public IWiredNode getNode() + { + return node; + } + + @Override + public void networkChanged( @Nonnull IWiredNetworkChange change ) + { + remotePeripherals.keySet().removeAll( change.peripheralsRemoved().keySet() ); + remotePeripherals.putAll( change.peripheralsAdded() ); + } + + public NetworkElement addPeripheral( String name ) + { + localPeripherals.put( name, new NetworkPeripheral() ); + getNode().updatePeripherals( localPeripherals ); + return this; + } + + @Nonnull + public Map allPeripherals() + { + return remotePeripherals; + } + } + + private static class NetworkPeripheral implements IPeripheral + { + @Nonnull + @Override + public String getType() + { + return "test"; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } + + private static class Grid + { + private final int size; + private final T[] box; + + @SuppressWarnings( "unchecked" ) + Grid( int size ) + { + this.size = size; + this.box = (T[]) new Object[size * size * size]; + } + + public T get( BlockPos pos ) + { + int x = pos.getX(), y = pos.getY(), z = pos.getZ(); + + return x >= 0 && x < size && y >= 0 && y < size && z >= 0 && z < size + ? box[x * size * size + y * size + z] + : null; + } + + public void forEach( BiConsumer transform ) + { + for( int x = 0; x < size; x++ ) + { + for( int y = 0; y < size; y++ ) + { + for( int z = 0; z < size; z++ ) + { + transform.accept( box[x * size * size + y * size + z], new BlockPos( x, y, z ) ); + } + } + } + } + + public void map( BiFunction transform ) + { + for( int x = 0; x < size; x++ ) + { + for( int y = 0; y < size; y++ ) + { + for( int z = 0; z < size; z++ ) + { + box[x * size * size + y * size + z] = transform.apply( box[x * size * size + y * size + z], new BlockPos( x, y, z ) ); + } + } + } + } + } + + private static Set nodes( IWiredNetwork network ) + { + return ((WiredNetwork) network).nodes; + } + + private static Set neighbours( IWiredNode node ) + { + return ((WiredNode) node).neighbours; + } +} diff --git a/src/test/java/dan200/computercraft/utils/CallCounter.java b/src/test/java/dan200/computercraft/utils/CallCounter.java new file mode 100644 index 000000000..5dbae63f7 --- /dev/null +++ b/src/test/java/dan200/computercraft/utils/CallCounter.java @@ -0,0 +1,34 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CallCounter implements Runnable +{ + private int timesCalled = 0; + + @Override + public void run() + { + timesCalled++; + } + + public void assertCalledTimes( int expectedTimesCalled ) + { + assertEquals( expectedTimesCalled, timesCalled, "Callback was not called the correct number of times" ); + } + + public void assertNotCalled() + { + assertEquals( 0, timesCalled, "Should never have been called." ); + } + + public void reset() + { + this.timesCalled = 0; + } +} diff --git a/src/test/kotlin/dan200/computercraft/client/sound/DfpwmStreamTest.java b/src/test/kotlin/dan200/computercraft/client/sound/DfpwmStreamTest.java new file mode 100644 index 000000000..52a4958a9 --- /dev/null +++ b/src/test/kotlin/dan200/computercraft/client/sound/DfpwmStreamTest.java @@ -0,0 +1,40 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.sound; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import org.junit.jupiter.api.Test; + +import java.nio.ByteBuffer; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DfpwmStreamTest +{ + @Test + public void testDecodesBytes() + { + DfpwmStream stream = new DfpwmStream(); + + ByteBuf input = ByteBufAllocator.DEFAULT.buffer(); + input.writeBytes( new byte[] { 43, -31, 33, 44, 30, -16, -85, 23, -3, -55, 46, -70, 68, -67, 74, -96, -68, 16, 94, -87, -5, 87, 11, -16, 19, 92, 85, -71, 126, 5, -84, 64, 17, -6, 85, -11, -1, -87, -12, 1, 85, -56, 33, -80, 82, 104, -93, 17, 126, 23, 91, -30, 37, -32, 117, -72, -58, 11, -76, 19, -108, 86, -65, -10, -1, -68, -25, 10, -46, 85, 124, -54, 15, -24, 43, -94, 117, 63, -36, 15, -6, 88, 87, -26, -83, 106, 41, 13, -28, -113, -10, -66, 119, -87, -113, 68, -55, 40, -107, 62, 20, 72, 3, -96, 114, -87, -2, 39, -104, 30, 20, 42, 84, 24, 47, 64, 43, 61, -35, 95, -65, 42, 61, 42, -50, 4, -9, 81 } ); + stream.push( input ); + + byte[] values = new byte[1024]; + ByteBuffer buffer = stream.read( 2048 ); + assertEquals( 1024, buffer.remaining(), "Must have read 1024 bytes" ); + buffer.get( values ); + assertEquals( 0, buffer.remaining() ); + + assertArrayEquals( + new byte[] { -127, -126, -126, -126, -126, -126, -126, -127, -127, -127, -128, 127, 126, 126, 127, -128, -127, -128, 127, 125, 123, 123, 123, 121, 119, 117, 117, 119, 119, 119, 119, 118, 116, 116, 118, 120, 122, 122, 120, 118, 116, 114, 112, 110, 111, 113, 116, 119, 122, 125, 126, 126, 126, 126, 126, 126, -128, -125, -122, -121, -121, -121, -124, -127, -127, -127, -127, -125, -123, -121, -119, -116, -113, -113, -116, -116, -116, -119, -119, -117, -116, -116, -114, -112, -111, -111, -111, -114, -117, -117, -117, -118, -116, -114, -114, -115, -115, -118, -119, -119, -121, -123, -124, -124, -124, -124, -124, -122, -120, -118, -118, -118, -118, -118, -118, -118, -119, -120, -120, -120, -121, -122, -124, -126, -128, -128, -128, -128, -128, 127, 127, -128, -127, -125, -125, -125, -125, -126, -128, 126, 126, 126, 125, 123, 121, 121, 123, 125, 127, 127, 127, 127, 127, 127, 126, 126, 127, 127, 127, 127, -128, -127, -127, -127, -126, -125, -124, -123, -122, -121, -119, -119, -119, -119, -119, -119, -119, -118, -118, -118, -118, -119, -120, -121, -122, -124, -126, -128, -128, -126, -124, -122, -120, -118, -118, -120, -121, -121, -123, -125, -127, 127, -128, -126, -124, -123, -123, -123, -124, -124, -124, -124, -124, -124, -124, -124, -124, -124, -125, -125, -124, -123, -123, -123, -123, -123, -122, -121, -120, -119, -118, -119, -119, -119, -119, -119, -120, -121, -122, -123, -125, -127, -127, -125, -125, -125, -125, -125, -125, -126, -127, -128, 127, 125, 125, 125, 125, 126, 125, 124, 124, 125, 124, 123, 122, 122, 123, 123, 124, 125, 126, -128, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -126, -125, -124, -123, -122, -121, -120, -118, -116, -114, -112, -110, -108, -108, -111, -112, -112, -113, -113, -113, -113, -115, -115, -115, -115, -114, -113, -112, -110, -110, -112, -114, -116, -118, -120, -123, -123, -123, -124, -124, -124, -124, -124, -124, -126, -128, 126, 126, 126, 124, 124, 126, -128, -128, 126, 124, 122, 122, 122, 120, 118, 116, 114, 112, 113, 115, 116, 117, 117, 117, 117, 115, 115, 115, 115, 115, 114, 112, 110, 110, 110, 110, 112, 112, 112, 114, 115, 114, 113, 113, 114, 114, 116, 117, 116, 115, 115, 116, 115, 114, 113, 113, 115, 117, 119, 121, 123, 123, 123, 125, 127, 127, 127, 127, 125, 123, 123, 125, 125, 125, 127, 127, 127, 127, 125, 125, 125, 124, 122, 122, 124, 126, -128, -128, -128, -128, 126, 126, 126, 125, 123, 121, 119, 117, 115, 115, 117, 119, 121, 122, 122, 122, 122, 124, 126, 126, 124, 122, 120, 121, 123, 125, 126, 126, 126, 126, -128, -128, 126, 124, 124, 126, -128, -126, -126, -127, -127, 127, 125, 123, 121, 118, 118, 118, 118, 120, 121, 121, 123, 125, 126, 124, 124, 124, 122, 120, 118, 116, 116, 116, 116, 116, 114, 115, 115, 115, 117, 117, 117, 117, 117, 117, 117, 119, 121, 123, 125, 127, 127, 127, 127, 127, -127, -127, -127, -126, -124, -122, -120, -118, -116, -114, -112, -110, -108, -106, -106, -109, -110, -108, -106, -104, -105, -106, -104, -102, -100, -101, -104, -105, -103, -100, -100, -100, -101, -102, -102, -105, -108, -111, -114, -114, -114, -117, -117, -117, -117, -115, -113, -112, -112, -112, -113, -113, -114, -114, -116, -118, -119, -117, -115, -113, -111, -111, -114, -115, -115, -116, -116, -118, -119, -117, -115, -113, -111, -109, -109, -112, -115, -118, -121, -124, -127, -127, -126, -126, -124, -121, -118, -115, -115, -115, -116, -116, -116, -119, -122, -122, -122, -125, -128, -128, -128, -128, -126, -125, -125, -125, -125, -123, -121, -121, -121, -119, -117, -115, -113, -110, -110, -113, -116, -119, -120, -118, -115, -115, -115, -113, -110, -107, -104, -101, -101, -105, -109, -113, -117, -118, -119, -119, -116, -112, -109, -106, -105, -109, -114, -115, -112, -112, -113, -113, -114, -111, -108, -108, -109, -109, -110, -111, -114, -115, -113, -113, -116, -117, -115, -112, -109, -109, -110, -108, -108, -109, -110, -110, -111, -111, -112, -112, -112, -113, -111, -111, -112, -112, -115, -116, -116, -117, -117, -119, -119, -119, -119, -117, -117, -119, -121, -123, -125, -127, -127, -127, 127, 127, -127, -125, -123, -121, -119, -117, -116, -119, -122, -122, -122, -122, -120, -120, -121, -119, -117, -115, -115, -116, -114, -112, -110, -108, -108, -108, -106, -104, -102, -103, -103, -101, -99, -100, -101, -102, -105, -106, -106, -107, -107, -108, -106, -104, -102, -100, -101, -104, -107, -107, -107, -110, -111, -111, -114, -117, -117, -117, -118, -118, -121, -122, -122, -124, -125, -123, -123, -125, -127, -127, -127, -127, -127, 127, 127, 127, 127, 127, 127, -128, 127, 127, -128, -128, -127, -126, -125, -124, -125, -127, 127, 125, 125, 125, 125, 126, 125, 124, 122, 120, 118, 118, 118, 116, 116, 116, 116, 118, 118, 117, 116, 114, 112, 110, 108, 106, 104, 102, 100, 101, 101, 102, 102, 103, 103, 101, 102, 104, 106, 106, 106, 106, 104, 104, 104, 104, 105, 105, 106, 106, 107, 108, 109, 111, 113, 115, 117, 119, 121, 121, 119, 119, 119, 117, 115, 113, 111, 112, 114, 115, 113, 114, 114, 114, 116, 118, 120, 121, 119, 117, 115, 113, 114, 114, 115, 115, 113, 111, 109, 110, 110, 111, 111, 112, 112, 110, 108, 106, 107, 107, 107, 107, 107, 108, 107, 106, 104, 104, 106, 106, 104, 102, 103, 105, 107, 109, 110, 111, 111, 109, 107, 105, 103, 101, 99, 97, 98, 99, 100, 102, 103, 104, 104, 105, 105, 103, 104, 104, 104, 106, 108, 110, 110, 108, 108, 108, 108, 110, 112, 112, 112, 114, 116, 118, 120, 122, 124, 124, 124, 124, 124, 126, -128, -126, -124, -122, -122, -123, -123, -123, -123, -123, -123, -123, -123, -125, -125, -125, -125, -124, -123, -122, -123, -125, -127, -127, -127, -127, -127, -127, -127, -128, 127, 127, -128, -127, -127, -128, -128, -127, -127, -128, -128, -128, 127, 126, 125, 124, 124, 126, -128, -128, -128, -127, -125, -123, -121, -121, -123, -125, -125, -125, -125, -125 }, + values, + "Decoded values must match." + ); + } +} diff --git a/src/test/resources/benchmark.lua b/src/test/resources/benchmark.lua new file mode 100644 index 000000000..dbbef23a1 --- /dev/null +++ b/src/test/resources/benchmark.lua @@ -0,0 +1,24 @@ +local function log(msg) + print(msg) + if assertion then assertion.log(msg) end +end + +local function run(name, n, f, ...) + sleep(0) + local s = os.epoch("utc") + for _ = 1, n do f(...) end + local e = os.epoch("utc") - s + log(("%10s %.2fs %.fop/s"):format(name, e*1e-3, n/e)) +end + +local function run5(...) for _ = 1, 5 do run(...) end end + +local native = term.native() +local x, y = native.getCursorPos() + +log("Starting the benchmark") +run5("redstone.getAnalogInput", 1e7, redstone.getAnalogInput, "top") +run5("term.getCursorPos", 2e7, native.getCursorPos) +run5("term.setCursorPos", 2e7, native.setCursorPos, x, y) + +if assertion then assertion.assert(true) end diff --git a/src/test/resources/test-rom/data/dump-args.lua b/src/test/resources/test-rom/data/dump-args.lua new file mode 100644 index 000000000..3772a43ec --- /dev/null +++ b/src/test/resources/test-rom/data/dump-args.lua @@ -0,0 +1 @@ +_G.__arg = _ENV.arg diff --git a/src/test/resources/test-rom/data/json-parsing/LICENSE b/src/test/resources/test-rom/data/json-parsing/LICENSE new file mode 100644 index 000000000..c4b3621d5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Nicolas Seriot + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/test/resources/test-rom/data/json-parsing/README.md b/src/test/resources/test-rom/data/json-parsing/README.md new file mode 100644 index 000000000..d0d801887 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/README.md @@ -0,0 +1,9 @@ +# JSON Parsing Test Suite + +This is a collection of JSON test cases from [nst/JSONTestSuite][gh]. We simply +determine whether an object is succesfully parsed or not, and do not check the +contents. + +See `LICENSE` for copyright information. + +[gh]: https://github.com/nst/JSONTestSuite diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_double_huge_neg_exp.json b/src/test/resources/test-rom/data/json-parsing/i_number_double_huge_neg_exp.json new file mode 100644 index 000000000..ae4c7b71f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_double_huge_neg_exp.json @@ -0,0 +1 @@ +[123.456e-789] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_huge_exp.json b/src/test/resources/test-rom/data/json-parsing/i_number_huge_exp.json new file mode 100644 index 000000000..9b5efa236 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_huge_exp.json @@ -0,0 +1 @@ +[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_neg_int_huge_exp.json b/src/test/resources/test-rom/data/json-parsing/i_number_neg_int_huge_exp.json new file mode 100644 index 000000000..3abd58a5c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_neg_int_huge_exp.json @@ -0,0 +1 @@ +[-1e+9999] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_pos_double_huge_exp.json b/src/test/resources/test-rom/data/json-parsing/i_number_pos_double_huge_exp.json new file mode 100644 index 000000000..e10a7eb62 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_pos_double_huge_exp.json @@ -0,0 +1 @@ +[1.5e+9999] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_real_neg_overflow.json b/src/test/resources/test-rom/data/json-parsing/i_number_real_neg_overflow.json new file mode 100644 index 000000000..3d628a994 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_real_neg_overflow.json @@ -0,0 +1 @@ +[-123123e100000] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_real_pos_overflow.json b/src/test/resources/test-rom/data/json-parsing/i_number_real_pos_overflow.json new file mode 100644 index 000000000..54d7d3dcd --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_real_pos_overflow.json @@ -0,0 +1 @@ +[123123e100000] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_real_underflow.json b/src/test/resources/test-rom/data/json-parsing/i_number_real_underflow.json new file mode 100644 index 000000000..c5236eb26 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_real_underflow.json @@ -0,0 +1 @@ +[123e-10000000] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_too_big_neg_int.json b/src/test/resources/test-rom/data/json-parsing/i_number_too_big_neg_int.json new file mode 100644 index 000000000..dfa384619 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_too_big_neg_int.json @@ -0,0 +1 @@ +[-123123123123123123123123123123] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_too_big_pos_int.json b/src/test/resources/test-rom/data/json-parsing/i_number_too_big_pos_int.json new file mode 100644 index 000000000..338a8c3c0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_too_big_pos_int.json @@ -0,0 +1 @@ +[100000000000000000000] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_very_big_negative_int.json b/src/test/resources/test-rom/data/json-parsing/i_number_very_big_negative_int.json new file mode 100644 index 000000000..e2d9738c2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_very_big_negative_int.json @@ -0,0 +1 @@ +[-237462374673276894279832749832423479823246327846] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_object_key_lone_2nd_surrogate.json b/src/test/resources/test-rom/data/json-parsing/i_object_key_lone_2nd_surrogate.json new file mode 100644 index 000000000..5be7ebaf9 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_object_key_lone_2nd_surrogate.json @@ -0,0 +1 @@ +{"\uDFAA":0} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_1st_surrogate_but_2nd_missing.json b/src/test/resources/test-rom/data/json-parsing/i_string_1st_surrogate_but_2nd_missing.json new file mode 100644 index 000000000..3b9e37c67 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_1st_surrogate_but_2nd_missing.json @@ -0,0 +1 @@ +["\uDADA"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_1st_valid_surrogate_2nd_invalid.json b/src/test/resources/test-rom/data/json-parsing/i_string_1st_valid_surrogate_2nd_invalid.json new file mode 100644 index 000000000..487592832 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_1st_valid_surrogate_2nd_invalid.json @@ -0,0 +1 @@ +["\uD888\u1234"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_UTF-16LE_with_BOM.json b/src/test/resources/test-rom/data/json-parsing/i_string_UTF-16LE_with_BOM.json new file mode 100644 index 000000000..2a79c0629 Binary files /dev/null and b/src/test/resources/test-rom/data/json-parsing/i_string_UTF-16LE_with_BOM.json differ diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_UTF-8_invalid_sequence.json b/src/test/resources/test-rom/data/json-parsing/i_string_UTF-8_invalid_sequence.json new file mode 100644 index 000000000..e2a968a15 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_UTF-8_invalid_sequence.json @@ -0,0 +1 @@ +["日шú"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_UTF8_surrogate_U+D800.json b/src/test/resources/test-rom/data/json-parsing/i_string_UTF8_surrogate_U+D800.json new file mode 100644 index 000000000..916bff920 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_UTF8_surrogate_U+D800.json @@ -0,0 +1 @@ +["í €"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_and_escape_valid.json b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_and_escape_valid.json new file mode 100644 index 000000000..3cb11d229 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_and_escape_valid.json @@ -0,0 +1 @@ +["\uD800\n"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_pair.json b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_pair.json new file mode 100644 index 000000000..38ec23bb0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_pair.json @@ -0,0 +1 @@ +["\uDd1ea"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogates_escape_valid.json b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogates_escape_valid.json new file mode 100644 index 000000000..c9cd6f6c3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogates_escape_valid.json @@ -0,0 +1 @@ +["\uD800\uD800\n"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_invalid_lonely_surrogate.json b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_lonely_surrogate.json new file mode 100644 index 000000000..3abbd8d8d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_lonely_surrogate.json @@ -0,0 +1 @@ +["\ud800"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_invalid_surrogate.json b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_surrogate.json new file mode 100644 index 000000000..ffddc04f5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_surrogate.json @@ -0,0 +1 @@ +["\ud800abc"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_invalid_utf-8.json b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_utf-8.json new file mode 100644 index 000000000..8e45a7eca --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_utf-8.json @@ -0,0 +1 @@ +["ÿ"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_inverted_surrogates_U+1D11E.json b/src/test/resources/test-rom/data/json-parsing/i_string_inverted_surrogates_U+1D11E.json new file mode 100644 index 000000000..0d5456cc3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_inverted_surrogates_U+1D11E.json @@ -0,0 +1 @@ +["\uDd1e\uD834"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_iso_latin_1.json b/src/test/resources/test-rom/data/json-parsing/i_string_iso_latin_1.json new file mode 100644 index 000000000..9389c9823 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_iso_latin_1.json @@ -0,0 +1 @@ +["é"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_lone_second_surrogate.json b/src/test/resources/test-rom/data/json-parsing/i_string_lone_second_surrogate.json new file mode 100644 index 000000000..1dbd397f3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_lone_second_surrogate.json @@ -0,0 +1 @@ +["\uDFAA"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_lone_utf8_continuation_byte.json b/src/test/resources/test-rom/data/json-parsing/i_string_lone_utf8_continuation_byte.json new file mode 100644 index 000000000..729337c0a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_lone_utf8_continuation_byte.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_not_in_unicode_range.json b/src/test/resources/test-rom/data/json-parsing/i_string_not_in_unicode_range.json new file mode 100644 index 000000000..df90a2916 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_not_in_unicode_range.json @@ -0,0 +1 @@ +["ô¿¿¿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_2_bytes.json b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_2_bytes.json new file mode 100644 index 000000000..c8cee5e0a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_2_bytes.json @@ -0,0 +1 @@ +["À¯"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes.json b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes.json new file mode 100644 index 000000000..9a91da791 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes.json @@ -0,0 +1 @@ +["üƒ¿¿¿¿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes_null.json b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes_null.json new file mode 100644 index 000000000..d24fffdd9 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes_null.json @@ -0,0 +1 @@ +["ü€€€€€"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_truncated-utf-8.json b/src/test/resources/test-rom/data/json-parsing/i_string_truncated-utf-8.json new file mode 100644 index 000000000..63c7777fb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_truncated-utf-8.json @@ -0,0 +1 @@ +["àÿ"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_utf16BE_no_BOM.json b/src/test/resources/test-rom/data/json-parsing/i_string_utf16BE_no_BOM.json new file mode 100644 index 000000000..57e5392ff Binary files /dev/null and b/src/test/resources/test-rom/data/json-parsing/i_string_utf16BE_no_BOM.json differ diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_utf16LE_no_BOM.json b/src/test/resources/test-rom/data/json-parsing/i_string_utf16LE_no_BOM.json new file mode 100644 index 000000000..c49c1b25d Binary files /dev/null and b/src/test/resources/test-rom/data/json-parsing/i_string_utf16LE_no_BOM.json differ diff --git a/src/test/resources/test-rom/data/json-parsing/i_structure_500_nested_arrays.json b/src/test/resources/test-rom/data/json-parsing/i_structure_500_nested_arrays.json new file mode 100644 index 000000000..711840589 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_structure_500_nested_arrays.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_structure_UTF-8_BOM_empty_object.json b/src/test/resources/test-rom/data/json-parsing/i_structure_UTF-8_BOM_empty_object.json new file mode 100644 index 000000000..22fdca1b2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_structure_UTF-8_BOM_empty_object.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_1_true_without_comma.json b/src/test/resources/test-rom/data/json-parsing/n_array_1_true_without_comma.json new file mode 100644 index 000000000..c14e3f6b1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_1_true_without_comma.json @@ -0,0 +1 @@ +[1 true] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_a_invalid_utf8.json b/src/test/resources/test-rom/data/json-parsing/n_array_a_invalid_utf8.json new file mode 100644 index 000000000..38a86e2e6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_a_invalid_utf8.json @@ -0,0 +1 @@ +[aå] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_colon_instead_of_comma.json b/src/test/resources/test-rom/data/json-parsing/n_array_colon_instead_of_comma.json new file mode 100644 index 000000000..0d02ad448 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_colon_instead_of_comma.json @@ -0,0 +1 @@ +["": 1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_comma_after_close.json b/src/test/resources/test-rom/data/json-parsing/n_array_comma_after_close.json new file mode 100644 index 000000000..2ccba8d95 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_comma_after_close.json @@ -0,0 +1 @@ +[""], \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_comma_and_number.json b/src/test/resources/test-rom/data/json-parsing/n_array_comma_and_number.json new file mode 100644 index 000000000..d2c84e374 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_comma_and_number.json @@ -0,0 +1 @@ +[,1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_double_comma.json b/src/test/resources/test-rom/data/json-parsing/n_array_double_comma.json new file mode 100644 index 000000000..0431712bc --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_double_comma.json @@ -0,0 +1 @@ +[1,,2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_double_extra_comma.json b/src/test/resources/test-rom/data/json-parsing/n_array_double_extra_comma.json new file mode 100644 index 000000000..3f01d3129 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_double_extra_comma.json @@ -0,0 +1 @@ +["x",,] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_extra_close.json b/src/test/resources/test-rom/data/json-parsing/n_array_extra_close.json new file mode 100644 index 000000000..c12f9fae1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_extra_close.json @@ -0,0 +1 @@ +["x"]] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_extra_comma.json b/src/test/resources/test-rom/data/json-parsing/n_array_extra_comma.json new file mode 100644 index 000000000..5f8ce18e4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_extra_comma.json @@ -0,0 +1 @@ +["",] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_incomplete.json b/src/test/resources/test-rom/data/json-parsing/n_array_incomplete.json new file mode 100644 index 000000000..cc65b0b51 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_incomplete.json @@ -0,0 +1 @@ +["x" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_incomplete_invalid_value.json b/src/test/resources/test-rom/data/json-parsing/n_array_incomplete_invalid_value.json new file mode 100644 index 000000000..c21a8f6cf --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_incomplete_invalid_value.json @@ -0,0 +1 @@ +[x \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_inner_array_no_comma.json b/src/test/resources/test-rom/data/json-parsing/n_array_inner_array_no_comma.json new file mode 100644 index 000000000..c70b71647 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_inner_array_no_comma.json @@ -0,0 +1 @@ +[3[4]] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_invalid_utf8.json b/src/test/resources/test-rom/data/json-parsing/n_array_invalid_utf8.json new file mode 100644 index 000000000..6099d3441 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_invalid_utf8.json @@ -0,0 +1 @@ +[ÿ] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_items_separated_by_semicolon.json b/src/test/resources/test-rom/data/json-parsing/n_array_items_separated_by_semicolon.json new file mode 100644 index 000000000..d4bd7314c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_items_separated_by_semicolon.json @@ -0,0 +1 @@ +[1:2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_just_comma.json b/src/test/resources/test-rom/data/json-parsing/n_array_just_comma.json new file mode 100644 index 000000000..9d7077c68 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_just_comma.json @@ -0,0 +1 @@ +[,] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_just_minus.json b/src/test/resources/test-rom/data/json-parsing/n_array_just_minus.json new file mode 100644 index 000000000..29501c6ca --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_just_minus.json @@ -0,0 +1 @@ +[-] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_missing_value.json b/src/test/resources/test-rom/data/json-parsing/n_array_missing_value.json new file mode 100644 index 000000000..3a6ba86f3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_missing_value.json @@ -0,0 +1 @@ +[ , ""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_newlines_unclosed.json b/src/test/resources/test-rom/data/json-parsing/n_array_newlines_unclosed.json new file mode 100644 index 000000000..646680065 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_newlines_unclosed.json @@ -0,0 +1,3 @@ +["a", +4 +,1, \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_number_and_comma.json b/src/test/resources/test-rom/data/json-parsing/n_array_number_and_comma.json new file mode 100644 index 000000000..13f6f1d18 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_number_and_comma.json @@ -0,0 +1 @@ +[1,] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_number_and_several_commas.json b/src/test/resources/test-rom/data/json-parsing/n_array_number_and_several_commas.json new file mode 100644 index 000000000..0ac408cb8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_number_and_several_commas.json @@ -0,0 +1 @@ +[1,,] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_spaces_vertical_tab_formfeed.json b/src/test/resources/test-rom/data/json-parsing/n_array_spaces_vertical_tab_formfeed.json new file mode 100644 index 000000000..6cd7cf585 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_spaces_vertical_tab_formfeed.json @@ -0,0 +1 @@ +[" a"\f] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_star_inside.json b/src/test/resources/test-rom/data/json-parsing/n_array_star_inside.json new file mode 100644 index 000000000..5a5194647 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_star_inside.json @@ -0,0 +1 @@ +[*] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_unclosed.json b/src/test/resources/test-rom/data/json-parsing/n_array_unclosed.json new file mode 100644 index 000000000..060733059 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_unclosed.json @@ -0,0 +1 @@ +["" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_unclosed_trailing_comma.json b/src/test/resources/test-rom/data/json-parsing/n_array_unclosed_trailing_comma.json new file mode 100644 index 000000000..6604698ff --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_unclosed_trailing_comma.json @@ -0,0 +1 @@ +[1, \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_unclosed_with_new_lines.json b/src/test/resources/test-rom/data/json-parsing/n_array_unclosed_with_new_lines.json new file mode 100644 index 000000000..4f61de3fb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_unclosed_with_new_lines.json @@ -0,0 +1,3 @@ +[1, +1 +,1 \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_array_unclosed_with_object_inside.json b/src/test/resources/test-rom/data/json-parsing/n_array_unclosed_with_object_inside.json new file mode 100644 index 000000000..043a87e2d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_array_unclosed_with_object_inside.json @@ -0,0 +1 @@ +[{} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_incomplete_false.json b/src/test/resources/test-rom/data/json-parsing/n_incomplete_false.json new file mode 100644 index 000000000..eb18c6a14 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_incomplete_false.json @@ -0,0 +1 @@ +[fals] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_incomplete_null.json b/src/test/resources/test-rom/data/json-parsing/n_incomplete_null.json new file mode 100644 index 000000000..c18ef5385 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_incomplete_null.json @@ -0,0 +1 @@ +[nul] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_incomplete_true.json b/src/test/resources/test-rom/data/json-parsing/n_incomplete_true.json new file mode 100644 index 000000000..f451ac6d2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_incomplete_true.json @@ -0,0 +1 @@ +[tru] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_multidigit_number_then_00.json b/src/test/resources/test-rom/data/json-parsing/n_multidigit_number_then_00.json new file mode 100644 index 000000000..c22507b86 Binary files /dev/null and b/src/test/resources/test-rom/data/json-parsing/n_multidigit_number_then_00.json differ diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_++.json b/src/test/resources/test-rom/data/json-parsing/n_number_++.json new file mode 100644 index 000000000..bdb62aaf4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_++.json @@ -0,0 +1 @@ +[++1234] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_+1.json b/src/test/resources/test-rom/data/json-parsing/n_number_+1.json new file mode 100644 index 000000000..3cbe58c92 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_+1.json @@ -0,0 +1 @@ +[+1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_+Inf.json b/src/test/resources/test-rom/data/json-parsing/n_number_+Inf.json new file mode 100644 index 000000000..871ae14d5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_+Inf.json @@ -0,0 +1 @@ +[+Inf] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_-01.json b/src/test/resources/test-rom/data/json-parsing/n_number_-01.json new file mode 100644 index 000000000..0df32bac8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_-01.json @@ -0,0 +1 @@ +[-01] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_-1.0..json b/src/test/resources/test-rom/data/json-parsing/n_number_-1.0..json new file mode 100644 index 000000000..7cf55a85a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_-1.0..json @@ -0,0 +1 @@ +[-1.0.] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_-2..json b/src/test/resources/test-rom/data/json-parsing/n_number_-2..json new file mode 100644 index 000000000..9be84365d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_-2..json @@ -0,0 +1 @@ +[-2.] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_-NaN.json b/src/test/resources/test-rom/data/json-parsing/n_number_-NaN.json new file mode 100644 index 000000000..f61615d40 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_-NaN.json @@ -0,0 +1 @@ +[-NaN] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_.-1.json b/src/test/resources/test-rom/data/json-parsing/n_number_.-1.json new file mode 100644 index 000000000..1c9f2dd1b --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_.-1.json @@ -0,0 +1 @@ +[.-1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_.2e-3.json b/src/test/resources/test-rom/data/json-parsing/n_number_.2e-3.json new file mode 100644 index 000000000..c6c976f25 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_.2e-3.json @@ -0,0 +1 @@ +[.2e-3] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_0.1.2.json b/src/test/resources/test-rom/data/json-parsing/n_number_0.1.2.json new file mode 100644 index 000000000..c83a25621 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_0.1.2.json @@ -0,0 +1 @@ +[0.1.2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_0.3e+.json b/src/test/resources/test-rom/data/json-parsing/n_number_0.3e+.json new file mode 100644 index 000000000..a55a1bfef --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_0.3e+.json @@ -0,0 +1 @@ +[0.3e+] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_0.3e.json b/src/test/resources/test-rom/data/json-parsing/n_number_0.3e.json new file mode 100644 index 000000000..3dd5df4b3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_0.3e.json @@ -0,0 +1 @@ +[0.3e] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_0.e1.json b/src/test/resources/test-rom/data/json-parsing/n_number_0.e1.json new file mode 100644 index 000000000..c92c71ccb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_0.e1.json @@ -0,0 +1 @@ +[0.e1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_0_capital_E+.json b/src/test/resources/test-rom/data/json-parsing/n_number_0_capital_E+.json new file mode 100644 index 000000000..3ba2c7d6d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_0_capital_E+.json @@ -0,0 +1 @@ +[0E+] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_0_capital_E.json b/src/test/resources/test-rom/data/json-parsing/n_number_0_capital_E.json new file mode 100644 index 000000000..5301840d1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_0_capital_E.json @@ -0,0 +1 @@ +[0E] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_0e+.json b/src/test/resources/test-rom/data/json-parsing/n_number_0e+.json new file mode 100644 index 000000000..8ab0bc4b8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_0e+.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_0e.json b/src/test/resources/test-rom/data/json-parsing/n_number_0e.json new file mode 100644 index 000000000..47ec421bb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_0e.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_1.0e+.json b/src/test/resources/test-rom/data/json-parsing/n_number_1.0e+.json new file mode 100644 index 000000000..cd84b9f69 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_1.0e+.json @@ -0,0 +1 @@ +[1.0e+] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_1.0e-.json b/src/test/resources/test-rom/data/json-parsing/n_number_1.0e-.json new file mode 100644 index 000000000..4eb7afa0f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_1.0e-.json @@ -0,0 +1 @@ +[1.0e-] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_1.0e.json b/src/test/resources/test-rom/data/json-parsing/n_number_1.0e.json new file mode 100644 index 000000000..21753f4c7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_1.0e.json @@ -0,0 +1 @@ +[1.0e] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_1_000.json b/src/test/resources/test-rom/data/json-parsing/n_number_1_000.json new file mode 100644 index 000000000..7b18b66b3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_1_000.json @@ -0,0 +1 @@ +[1 000.0] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_1eE2.json b/src/test/resources/test-rom/data/json-parsing/n_number_1eE2.json new file mode 100644 index 000000000..4318a341d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_1eE2.json @@ -0,0 +1 @@ +[1eE2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_2.e+3.json b/src/test/resources/test-rom/data/json-parsing/n_number_2.e+3.json new file mode 100644 index 000000000..4442f394d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_2.e+3.json @@ -0,0 +1 @@ +[2.e+3] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_2.e-3.json b/src/test/resources/test-rom/data/json-parsing/n_number_2.e-3.json new file mode 100644 index 000000000..a65060edf --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_2.e-3.json @@ -0,0 +1 @@ +[2.e-3] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_2.e3.json b/src/test/resources/test-rom/data/json-parsing/n_number_2.e3.json new file mode 100644 index 000000000..66f7cf701 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_2.e3.json @@ -0,0 +1 @@ +[2.e3] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_9.e+.json b/src/test/resources/test-rom/data/json-parsing/n_number_9.e+.json new file mode 100644 index 000000000..732a7b11c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_9.e+.json @@ -0,0 +1 @@ +[9.e+] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_Inf.json b/src/test/resources/test-rom/data/json-parsing/n_number_Inf.json new file mode 100644 index 000000000..c40c734c3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_Inf.json @@ -0,0 +1 @@ +[Inf] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_NaN.json b/src/test/resources/test-rom/data/json-parsing/n_number_NaN.json new file mode 100644 index 000000000..499231790 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_NaN.json @@ -0,0 +1 @@ +[NaN] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_U+FF11_fullwidth_digit_one.json b/src/test/resources/test-rom/data/json-parsing/n_number_U+FF11_fullwidth_digit_one.json new file mode 100644 index 000000000..b14587e5e --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_U+FF11_fullwidth_digit_one.json @@ -0,0 +1 @@ +[1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_expression.json b/src/test/resources/test-rom/data/json-parsing/n_number_expression.json new file mode 100644 index 000000000..76fdbc8a4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_expression.json @@ -0,0 +1 @@ +[1+2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_hex_1_digit.json b/src/test/resources/test-rom/data/json-parsing/n_number_hex_1_digit.json new file mode 100644 index 000000000..3b214880c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_hex_1_digit.json @@ -0,0 +1 @@ +[0x1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_hex_2_digits.json b/src/test/resources/test-rom/data/json-parsing/n_number_hex_2_digits.json new file mode 100644 index 000000000..83e516ab0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_hex_2_digits.json @@ -0,0 +1 @@ +[0x42] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_infinity.json b/src/test/resources/test-rom/data/json-parsing/n_number_infinity.json new file mode 100644 index 000000000..8c2baf783 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_infinity.json @@ -0,0 +1 @@ +[Infinity] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_invalid+-.json b/src/test/resources/test-rom/data/json-parsing/n_number_invalid+-.json new file mode 100644 index 000000000..1cce602b5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_invalid+-.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_invalid-negative-real.json b/src/test/resources/test-rom/data/json-parsing/n_number_invalid-negative-real.json new file mode 100644 index 000000000..5fc3c1efb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_invalid-negative-real.json @@ -0,0 +1 @@ +[-123.123foo] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-bigger-int.json b/src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-bigger-int.json new file mode 100644 index 000000000..3b97e580e --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-bigger-int.json @@ -0,0 +1 @@ +[123å] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-exponent.json b/src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-exponent.json new file mode 100644 index 000000000..ea35d723c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-exponent.json @@ -0,0 +1 @@ +[1e1å] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-int.json b/src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-int.json new file mode 100644 index 000000000..371226e4c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-int.json @@ -0,0 +1 @@ +[0å] diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_minus_infinity.json b/src/test/resources/test-rom/data/json-parsing/n_number_minus_infinity.json new file mode 100644 index 000000000..cf4133d22 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_minus_infinity.json @@ -0,0 +1 @@ +[-Infinity] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_minus_sign_with_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_number_minus_sign_with_trailing_garbage.json new file mode 100644 index 000000000..a6d8e78e7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_minus_sign_with_trailing_garbage.json @@ -0,0 +1 @@ +[-foo] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_minus_space_1.json b/src/test/resources/test-rom/data/json-parsing/n_number_minus_space_1.json new file mode 100644 index 000000000..9a5ebedf6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_minus_space_1.json @@ -0,0 +1 @@ +[- 1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_neg_int_starting_with_zero.json b/src/test/resources/test-rom/data/json-parsing/n_number_neg_int_starting_with_zero.json new file mode 100644 index 000000000..67af0960a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_neg_int_starting_with_zero.json @@ -0,0 +1 @@ +[-012] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_neg_real_without_int_part.json b/src/test/resources/test-rom/data/json-parsing/n_number_neg_real_without_int_part.json new file mode 100644 index 000000000..1f2a43496 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_neg_real_without_int_part.json @@ -0,0 +1 @@ +[-.123] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_neg_with_garbage_at_end.json b/src/test/resources/test-rom/data/json-parsing/n_number_neg_with_garbage_at_end.json new file mode 100644 index 000000000..2aa73119f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_neg_with_garbage_at_end.json @@ -0,0 +1 @@ +[-1x] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_real_garbage_after_e.json b/src/test/resources/test-rom/data/json-parsing/n_number_real_garbage_after_e.json new file mode 100644 index 000000000..9213dfca8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_real_garbage_after_e.json @@ -0,0 +1 @@ +[1ea] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_real_with_invalid_utf8_after_e.json b/src/test/resources/test-rom/data/json-parsing/n_number_real_with_invalid_utf8_after_e.json new file mode 100644 index 000000000..1e52ef964 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_real_with_invalid_utf8_after_e.json @@ -0,0 +1 @@ +[1eå] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_real_without_fractional_part.json b/src/test/resources/test-rom/data/json-parsing/n_number_real_without_fractional_part.json new file mode 100644 index 000000000..1de287cf8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_real_without_fractional_part.json @@ -0,0 +1 @@ +[1.] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_starting_with_dot.json b/src/test/resources/test-rom/data/json-parsing/n_number_starting_with_dot.json new file mode 100644 index 000000000..f682dbdce --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_starting_with_dot.json @@ -0,0 +1 @@ +[.123] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_with_alpha.json b/src/test/resources/test-rom/data/json-parsing/n_number_with_alpha.json new file mode 100644 index 000000000..1e42d8182 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_with_alpha.json @@ -0,0 +1 @@ +[1.2a-3] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_with_alpha_char.json b/src/test/resources/test-rom/data/json-parsing/n_number_with_alpha_char.json new file mode 100644 index 000000000..b79daccb8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_with_alpha_char.json @@ -0,0 +1 @@ +[1.8011670033376514H-308] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_number_with_leading_zero.json b/src/test/resources/test-rom/data/json-parsing/n_number_with_leading_zero.json new file mode 100644 index 000000000..7106da1f3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_number_with_leading_zero.json @@ -0,0 +1 @@ +[012] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_bad_value.json b/src/test/resources/test-rom/data/json-parsing/n_object_bad_value.json new file mode 100644 index 000000000..a03a8c03b --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_bad_value.json @@ -0,0 +1 @@ +["x", truth] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_bracket_key.json b/src/test/resources/test-rom/data/json-parsing/n_object_bracket_key.json new file mode 100644 index 000000000..cc443b483 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_bracket_key.json @@ -0,0 +1 @@ +{[: "x"} diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_comma_instead_of_colon.json b/src/test/resources/test-rom/data/json-parsing/n_object_comma_instead_of_colon.json new file mode 100644 index 000000000..8d5637708 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_comma_instead_of_colon.json @@ -0,0 +1 @@ +{"x", null} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_double_colon.json b/src/test/resources/test-rom/data/json-parsing/n_object_double_colon.json new file mode 100644 index 000000000..80e8c7b89 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_double_colon.json @@ -0,0 +1 @@ +{"x"::"b"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_emoji.json b/src/test/resources/test-rom/data/json-parsing/n_object_emoji.json new file mode 100644 index 000000000..cb4078eaa --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_emoji.json @@ -0,0 +1 @@ +{🇨🇭} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_garbage_at_end.json b/src/test/resources/test-rom/data/json-parsing/n_object_garbage_at_end.json new file mode 100644 index 000000000..80c42cbad --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_garbage_at_end.json @@ -0,0 +1 @@ +{"a":"a" 123} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_key_with_single_quotes.json b/src/test/resources/test-rom/data/json-parsing/n_object_key_with_single_quotes.json new file mode 100644 index 000000000..77c327599 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_key_with_single_quotes.json @@ -0,0 +1 @@ +{key: 'value'} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json b/src/test/resources/test-rom/data/json-parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json new file mode 100644 index 000000000..aa2cb637c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json @@ -0,0 +1 @@ +{"¹":"0",} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_missing_colon.json b/src/test/resources/test-rom/data/json-parsing/n_object_missing_colon.json new file mode 100644 index 000000000..b98eff62d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_missing_colon.json @@ -0,0 +1 @@ +{"a" b} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_missing_key.json b/src/test/resources/test-rom/data/json-parsing/n_object_missing_key.json new file mode 100644 index 000000000..b4fb0f528 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_missing_key.json @@ -0,0 +1 @@ +{:"b"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_missing_semicolon.json b/src/test/resources/test-rom/data/json-parsing/n_object_missing_semicolon.json new file mode 100644 index 000000000..e3451384f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_missing_semicolon.json @@ -0,0 +1 @@ +{"a" "b"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_missing_value.json b/src/test/resources/test-rom/data/json-parsing/n_object_missing_value.json new file mode 100644 index 000000000..3ef538a60 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_missing_value.json @@ -0,0 +1 @@ +{"a": \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_no-colon.json b/src/test/resources/test-rom/data/json-parsing/n_object_no-colon.json new file mode 100644 index 000000000..f3797b357 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_no-colon.json @@ -0,0 +1 @@ +{"a" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_non_string_key.json b/src/test/resources/test-rom/data/json-parsing/n_object_non_string_key.json new file mode 100644 index 000000000..b9945b34b --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_non_string_key.json @@ -0,0 +1 @@ +{1:1} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_non_string_key_but_huge_number_instead.json b/src/test/resources/test-rom/data/json-parsing/n_object_non_string_key_but_huge_number_instead.json new file mode 100644 index 000000000..b37fa86c0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_non_string_key_but_huge_number_instead.json @@ -0,0 +1 @@ +{9999E9999:1} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_repeated_null_null.json b/src/test/resources/test-rom/data/json-parsing/n_object_repeated_null_null.json new file mode 100644 index 000000000..f7d2959d0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_repeated_null_null.json @@ -0,0 +1 @@ +{null:null,null:null} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_several_trailing_commas.json b/src/test/resources/test-rom/data/json-parsing/n_object_several_trailing_commas.json new file mode 100644 index 000000000..3c9afe8dc --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_several_trailing_commas.json @@ -0,0 +1 @@ +{"id":0,,,,,} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_single_quote.json b/src/test/resources/test-rom/data/json-parsing/n_object_single_quote.json new file mode 100644 index 000000000..e5cdf976a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_single_quote.json @@ -0,0 +1 @@ +{'a':0} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comma.json b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comma.json new file mode 100644 index 000000000..a4b025094 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comma.json @@ -0,0 +1 @@ +{"id":0,} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment.json b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment.json new file mode 100644 index 000000000..a372c6553 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment.json @@ -0,0 +1 @@ +{"a":"b"}/**/ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_open.json b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_open.json new file mode 100644 index 000000000..d557f41ca --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_open.json @@ -0,0 +1 @@ +{"a":"b"}/**// \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_slash_open.json b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_slash_open.json new file mode 100644 index 000000000..e335136c0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_slash_open.json @@ -0,0 +1 @@ +{"a":"b"}// \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_slash_open_incomplete.json b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_slash_open_incomplete.json new file mode 100644 index 000000000..d892e49f1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_slash_open_incomplete.json @@ -0,0 +1 @@ +{"a":"b"}/ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_two_commas_in_a_row.json b/src/test/resources/test-rom/data/json-parsing/n_object_two_commas_in_a_row.json new file mode 100644 index 000000000..7c639ae64 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_two_commas_in_a_row.json @@ -0,0 +1 @@ +{"a":"b",,"c":"d"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_unquoted_key.json b/src/test/resources/test-rom/data/json-parsing/n_object_unquoted_key.json new file mode 100644 index 000000000..8ba137293 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_unquoted_key.json @@ -0,0 +1 @@ +{a: "b"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_unterminated-value.json b/src/test/resources/test-rom/data/json-parsing/n_object_unterminated-value.json new file mode 100644 index 000000000..7fe699a6a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_unterminated-value.json @@ -0,0 +1 @@ +{"a":"a \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_with_single_string.json b/src/test/resources/test-rom/data/json-parsing/n_object_with_single_string.json new file mode 100644 index 000000000..d63f7fbb7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_with_single_string.json @@ -0,0 +1 @@ +{ "foo" : "bar", "a" } \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_object_with_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_object_with_trailing_garbage.json new file mode 100644 index 000000000..787c8f0a8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_object_with_trailing_garbage.json @@ -0,0 +1 @@ +{"a":"b"}# \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_single_space.json b/src/test/resources/test-rom/data/json-parsing/n_single_space.json new file mode 100644 index 000000000..0519ecba6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_single_space.json @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape.json b/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape.json new file mode 100644 index 000000000..acec66d8f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape.json @@ -0,0 +1 @@ +["\uD800\"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u.json b/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u.json new file mode 100644 index 000000000..e834b05e9 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u.json @@ -0,0 +1 @@ +["\uD800\u"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u1.json b/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u1.json new file mode 100644 index 000000000..a04cd3489 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u1.json @@ -0,0 +1 @@ +["\uD800\u1"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u1x.json b/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u1x.json new file mode 100644 index 000000000..bfbd23409 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u1x.json @@ -0,0 +1 @@ +["\uD800\u1x"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_accentuated_char_no_quotes.json b/src/test/resources/test-rom/data/json-parsing/n_string_accentuated_char_no_quotes.json new file mode 100644 index 000000000..fd6895693 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_accentuated_char_no_quotes.json @@ -0,0 +1 @@ +[é] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_backslash_00.json b/src/test/resources/test-rom/data/json-parsing/n_string_backslash_00.json new file mode 100644 index 000000000..b5bf267b5 Binary files /dev/null and b/src/test/resources/test-rom/data/json-parsing/n_string_backslash_00.json differ diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_escape_x.json b/src/test/resources/test-rom/data/json-parsing/n_string_escape_x.json new file mode 100644 index 000000000..fae291938 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_escape_x.json @@ -0,0 +1 @@ +["\x00"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_escaped_backslash_bad.json b/src/test/resources/test-rom/data/json-parsing/n_string_escaped_backslash_bad.json new file mode 100644 index 000000000..016fcb47e --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_escaped_backslash_bad.json @@ -0,0 +1 @@ +["\\\"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_escaped_ctrl_char_tab.json b/src/test/resources/test-rom/data/json-parsing/n_string_escaped_ctrl_char_tab.json new file mode 100644 index 000000000..f35ea382b --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_escaped_ctrl_char_tab.json @@ -0,0 +1 @@ +["\ "] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_escaped_emoji.json b/src/test/resources/test-rom/data/json-parsing/n_string_escaped_emoji.json new file mode 100644 index 000000000..a27775421 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_escaped_emoji.json @@ -0,0 +1 @@ +["\🌀"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_escape.json b/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_escape.json new file mode 100644 index 000000000..3415c33ca --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_escape.json @@ -0,0 +1 @@ +["\"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_escaped_character.json b/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_escaped_character.json new file mode 100644 index 000000000..0f2197ea2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_escaped_character.json @@ -0,0 +1 @@ +["\u00A"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_surrogate.json b/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_surrogate.json new file mode 100644 index 000000000..75504a656 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_surrogate.json @@ -0,0 +1 @@ +["\uD834\uDd"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_surrogate_escape_invalid.json b/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_surrogate_escape_invalid.json new file mode 100644 index 000000000..bd9656060 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_incomplete_surrogate_escape_invalid.json @@ -0,0 +1 @@ +["\uD800\uD800\x"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_invalid-utf-8-in-escape.json b/src/test/resources/test-rom/data/json-parsing/n_string_invalid-utf-8-in-escape.json new file mode 100644 index 000000000..0c4300643 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_invalid-utf-8-in-escape.json @@ -0,0 +1 @@ +["\uå"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_invalid_backslash_esc.json b/src/test/resources/test-rom/data/json-parsing/n_string_invalid_backslash_esc.json new file mode 100644 index 000000000..d1eb60921 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_invalid_backslash_esc.json @@ -0,0 +1 @@ +["\a"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_invalid_unicode_escape.json b/src/test/resources/test-rom/data/json-parsing/n_string_invalid_unicode_escape.json new file mode 100644 index 000000000..7608cb6ba --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_invalid_unicode_escape.json @@ -0,0 +1 @@ +["\uqqqq"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_invalid_utf8_after_escape.json b/src/test/resources/test-rom/data/json-parsing/n_string_invalid_utf8_after_escape.json new file mode 100644 index 000000000..2f757a25b --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_invalid_utf8_after_escape.json @@ -0,0 +1 @@ +["\å"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_leading_uescaped_thinspace.json b/src/test/resources/test-rom/data/json-parsing/n_string_leading_uescaped_thinspace.json new file mode 100644 index 000000000..7b297c636 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_leading_uescaped_thinspace.json @@ -0,0 +1 @@ +[\u0020"asd"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_no_quotes_with_bad_escape.json b/src/test/resources/test-rom/data/json-parsing/n_string_no_quotes_with_bad_escape.json new file mode 100644 index 000000000..01bc70aba --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_no_quotes_with_bad_escape.json @@ -0,0 +1 @@ +[\n] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_single_doublequote.json b/src/test/resources/test-rom/data/json-parsing/n_string_single_doublequote.json new file mode 100644 index 000000000..9d68933c4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_single_doublequote.json @@ -0,0 +1 @@ +" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_single_quote.json b/src/test/resources/test-rom/data/json-parsing/n_string_single_quote.json new file mode 100644 index 000000000..caff239bf --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_single_quote.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_single_string_no_double_quotes.json b/src/test/resources/test-rom/data/json-parsing/n_string_single_string_no_double_quotes.json new file mode 100644 index 000000000..f2ba8f84a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_single_string_no_double_quotes.json @@ -0,0 +1 @@ +abc \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_start_escape_unclosed.json b/src/test/resources/test-rom/data/json-parsing/n_string_start_escape_unclosed.json new file mode 100644 index 000000000..db62a46fc --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_start_escape_unclosed.json @@ -0,0 +1 @@ +["\ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_crtl_char.json b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_crtl_char.json new file mode 100644 index 000000000..9f2134807 Binary files /dev/null and b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_crtl_char.json differ diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_newline.json b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_newline.json new file mode 100644 index 000000000..700d36086 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_newline.json @@ -0,0 +1,2 @@ +["new +line"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_tab.json b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_tab.json new file mode 100644 index 000000000..160264a2d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_tab.json @@ -0,0 +1 @@ +[" "] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_unicode_CapitalU.json b/src/test/resources/test-rom/data/json-parsing/n_string_unicode_CapitalU.json new file mode 100644 index 000000000..17332bb17 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_unicode_CapitalU.json @@ -0,0 +1 @@ +"\UA66D" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_with_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_string_with_trailing_garbage.json new file mode 100644 index 000000000..efe3bd272 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_with_trailing_garbage.json @@ -0,0 +1 @@ +""x \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_100000_opening_arrays.json b/src/test/resources/test-rom/data/json-parsing/n_structure_100000_opening_arrays.json new file mode 100644 index 000000000..a4823eecc --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_100000_opening_arrays.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_U+2060_word_joined.json b/src/test/resources/test-rom/data/json-parsing/n_structure_U+2060_word_joined.json new file mode 100644 index 000000000..81156a699 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_U+2060_word_joined.json @@ -0,0 +1 @@ +[â ] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_UTF8_BOM_no_data.json b/src/test/resources/test-rom/data/json-parsing/n_structure_UTF8_BOM_no_data.json new file mode 100644 index 000000000..5f282702b --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_UTF8_BOM_no_data.json @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_..json b/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_..json new file mode 100644 index 000000000..a56fef0b0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_..json @@ -0,0 +1 @@ +<.> \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_null.json b/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_null.json new file mode 100644 index 000000000..617f26254 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_null.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_array_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_structure_array_trailing_garbage.json new file mode 100644 index 000000000..5a745e6f3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_array_trailing_garbage.json @@ -0,0 +1 @@ +[1]x \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_extra_array_close.json b/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_extra_array_close.json new file mode 100644 index 000000000..6cfb1398d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_extra_array_close.json @@ -0,0 +1 @@ +[1]] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_unclosed_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_unclosed_string.json new file mode 100644 index 000000000..ba6b1788b --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_unclosed_string.json @@ -0,0 +1 @@ +["asd] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_ascii-unicode-identifier.json b/src/test/resources/test-rom/data/json-parsing/n_structure_ascii-unicode-identifier.json new file mode 100644 index 000000000..ef2ab62fe --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_ascii-unicode-identifier.json @@ -0,0 +1 @@ +aÃ¥ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_capitalized_True.json b/src/test/resources/test-rom/data/json-parsing/n_structure_capitalized_True.json new file mode 100644 index 000000000..7cd88469a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_capitalized_True.json @@ -0,0 +1 @@ +[True] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_close_unopened_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_close_unopened_array.json new file mode 100644 index 000000000..d2af0c646 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_close_unopened_array.json @@ -0,0 +1 @@ +1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_comma_instead_of_closing_brace.json b/src/test/resources/test-rom/data/json-parsing/n_structure_comma_instead_of_closing_brace.json new file mode 100644 index 000000000..ac61b8200 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_comma_instead_of_closing_brace.json @@ -0,0 +1 @@ +{"x": true, \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_double_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_double_array.json new file mode 100644 index 000000000..058d1626e --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_double_array.json @@ -0,0 +1 @@ +[][] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_end_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_end_array.json new file mode 100644 index 000000000..54caf60b1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_end_array.json @@ -0,0 +1 @@ +] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_incomplete_UTF8_BOM.json b/src/test/resources/test-rom/data/json-parsing/n_structure_incomplete_UTF8_BOM.json new file mode 100644 index 000000000..bfcdd514f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_incomplete_UTF8_BOM.json @@ -0,0 +1 @@ +ï»{} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_lone-invalid-utf-8.json b/src/test/resources/test-rom/data/json-parsing/n_structure_lone-invalid-utf-8.json new file mode 100644 index 000000000..8b1296cad --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_lone-invalid-utf-8.json @@ -0,0 +1 @@ +å \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_lone-open-bracket.json b/src/test/resources/test-rom/data/json-parsing/n_structure_lone-open-bracket.json new file mode 100644 index 000000000..8e2f0bef1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_lone-open-bracket.json @@ -0,0 +1 @@ +[ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_no_data.json b/src/test/resources/test-rom/data/json-parsing/n_structure_no_data.json new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_null-byte-outside-string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_null-byte-outside-string.json new file mode 100644 index 000000000..326db1442 Binary files /dev/null and b/src/test/resources/test-rom/data/json-parsing/n_structure_null-byte-outside-string.json differ diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_number_with_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_structure_number_with_trailing_garbage.json new file mode 100644 index 000000000..0746539d2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_number_with_trailing_garbage.json @@ -0,0 +1 @@ +2@ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_object_followed_by_closing_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_object_followed_by_closing_object.json new file mode 100644 index 000000000..aa9ebaec5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_object_followed_by_closing_object.json @@ -0,0 +1 @@ +{}} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_object_unclosed_no_value.json b/src/test/resources/test-rom/data/json-parsing/n_structure_object_unclosed_no_value.json new file mode 100644 index 000000000..17d045147 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_object_unclosed_no_value.json @@ -0,0 +1 @@ +{"": \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_comment.json b/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_comment.json new file mode 100644 index 000000000..ed1b569b7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_comment.json @@ -0,0 +1 @@ +{"a":/*comment*/"b"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_trailing_garbage.json new file mode 100644 index 000000000..9ca2336d7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_trailing_garbage.json @@ -0,0 +1 @@ +{"a": true} "x" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_apostrophe.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_apostrophe.json new file mode 100644 index 000000000..8bebe3af0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_apostrophe.json @@ -0,0 +1 @@ +[' \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_comma.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_comma.json new file mode 100644 index 000000000..6295fdc36 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_comma.json @@ -0,0 +1 @@ +[, \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_object.json new file mode 100644 index 000000000..e870445b2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_object.json @@ -0,0 +1 @@ +[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"": diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_object.json new file mode 100644 index 000000000..7a63c8c57 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_object.json @@ -0,0 +1 @@ +[{ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_string.json new file mode 100644 index 000000000..9822a6baf --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_string.json @@ -0,0 +1 @@ +["a \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_string.json new file mode 100644 index 000000000..42a619362 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_string.json @@ -0,0 +1 @@ +["a" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object.json new file mode 100644 index 000000000..81750b96f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object.json @@ -0,0 +1 @@ +{ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_close_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_close_array.json new file mode 100644 index 000000000..eebc700a1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_close_array.json @@ -0,0 +1 @@ +{] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_comma.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_comma.json new file mode 100644 index 000000000..47bc9106f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_comma.json @@ -0,0 +1 @@ +{, \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_array.json new file mode 100644 index 000000000..381ede5de --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_array.json @@ -0,0 +1 @@ +{[ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_string.json new file mode 100644 index 000000000..328c30cd7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_string.json @@ -0,0 +1 @@ +{"a \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_string_with_apostrophes.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_string_with_apostrophes.json new file mode 100644 index 000000000..9dba17090 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_string_with_apostrophes.json @@ -0,0 +1 @@ +{'a' \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_open.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_open.json new file mode 100644 index 000000000..841fd5f86 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_open.json @@ -0,0 +1 @@ +["\{["\{["\{["\{ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_single_eacute.json b/src/test/resources/test-rom/data/json-parsing/n_structure_single_eacute.json new file mode 100644 index 000000000..92a39f398 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_single_eacute.json @@ -0,0 +1 @@ +é \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_single_star.json b/src/test/resources/test-rom/data/json-parsing/n_structure_single_star.json new file mode 100644 index 000000000..f59ec20aa --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_single_star.json @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_trailing_#.json b/src/test/resources/test-rom/data/json-parsing/n_structure_trailing_#.json new file mode 100644 index 000000000..898611087 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_trailing_#.json @@ -0,0 +1 @@ +{"a":"b"}#{} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_uescaped_LF_before_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_uescaped_LF_before_string.json new file mode 100644 index 000000000..df2f0f242 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_uescaped_LF_before_string.json @@ -0,0 +1 @@ +[\u000A""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array.json new file mode 100644 index 000000000..11209515c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array.json @@ -0,0 +1 @@ +[1 \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_partial_null.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_partial_null.json new file mode 100644 index 000000000..0d591762c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_partial_null.json @@ -0,0 +1 @@ +[ false, nul \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_false.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_false.json new file mode 100644 index 000000000..a2ff8504a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_false.json @@ -0,0 +1 @@ +[ true, fals \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_true.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_true.json new file mode 100644 index 000000000..3149e8f5a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_true.json @@ -0,0 +1 @@ +[ false, tru \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_object.json new file mode 100644 index 000000000..694d69dbd --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_object.json @@ -0,0 +1 @@ +{"asd":"asd" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unicode-identifier.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unicode-identifier.json new file mode 100644 index 000000000..7284aea33 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unicode-identifier.json @@ -0,0 +1 @@ +Ã¥ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_U+2060_word_joiner.json b/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_U+2060_word_joiner.json new file mode 100644 index 000000000..81156a699 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_U+2060_word_joiner.json @@ -0,0 +1 @@ +[â ] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_formfeed.json b/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_formfeed.json new file mode 100644 index 000000000..a9ea535d1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_formfeed.json @@ -0,0 +1 @@ +[ ] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/skip.lua b/src/test/resources/test-rom/data/json-parsing/skip.lua new file mode 100644 index 000000000..3b147c7b4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/skip.lua @@ -0,0 +1,21 @@ +local skip = { + -- Should fail, but pass. + -- We're too flexible on number formatting, but it's not a major concern. + "n_number_-01", + "n_number_-2.", + "n_number_0.e1", + "n_number_2.e3", + "n_number_2.e+3", + "n_number_2.e-3", + "n_number_neg_int_starting_with_zero", + "n_number_real_without_fractional_part", + "n_number_with_leading_zero", + + -- Should pass, but fail. + -- These two are due to stack overflows within the parser. + "n_structure_open_array_object", + "n_structure_100000_opening_arrays", +} + +for _, k in pairs(skip) do skip[k] = true end +return skip diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_arraysWithSpaces.json b/src/test/resources/test-rom/data/json-parsing/y_array_arraysWithSpaces.json new file mode 100644 index 000000000..582290798 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_arraysWithSpaces.json @@ -0,0 +1 @@ +[[] ] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_empty-string.json b/src/test/resources/test-rom/data/json-parsing/y_array_empty-string.json new file mode 100644 index 000000000..93b6be2bc --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_empty-string.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_empty.json b/src/test/resources/test-rom/data/json-parsing/y_array_empty.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_empty.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_ending_with_newline.json b/src/test/resources/test-rom/data/json-parsing/y_array_ending_with_newline.json new file mode 100644 index 000000000..eac5f7b46 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_ending_with_newline.json @@ -0,0 +1 @@ +["a"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_false.json b/src/test/resources/test-rom/data/json-parsing/y_array_false.json new file mode 100644 index 000000000..67b2f0760 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_false.json @@ -0,0 +1 @@ +[false] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_heterogeneous.json b/src/test/resources/test-rom/data/json-parsing/y_array_heterogeneous.json new file mode 100644 index 000000000..d3c1e2648 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_heterogeneous.json @@ -0,0 +1 @@ +[null, 1, "1", {}] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_null.json b/src/test/resources/test-rom/data/json-parsing/y_array_null.json new file mode 100644 index 000000000..500db4a86 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_null.json @@ -0,0 +1 @@ +[null] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_with_1_and_newline.json b/src/test/resources/test-rom/data/json-parsing/y_array_with_1_and_newline.json new file mode 100644 index 000000000..994825500 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_with_1_and_newline.json @@ -0,0 +1,2 @@ +[1 +] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_with_leading_space.json b/src/test/resources/test-rom/data/json-parsing/y_array_with_leading_space.json new file mode 100644 index 000000000..18bfe6422 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_with_leading_space.json @@ -0,0 +1 @@ + [1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_with_several_null.json b/src/test/resources/test-rom/data/json-parsing/y_array_with_several_null.json new file mode 100644 index 000000000..99f6c5d1d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_with_several_null.json @@ -0,0 +1 @@ +[1,null,null,null,2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_with_trailing_space.json b/src/test/resources/test-rom/data/json-parsing/y_array_with_trailing_space.json new file mode 100644 index 000000000..de9e7a944 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_with_trailing_space.json @@ -0,0 +1 @@ +[2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number.json b/src/test/resources/test-rom/data/json-parsing/y_number.json new file mode 100644 index 000000000..e5f5cc334 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number.json @@ -0,0 +1 @@ +[123e65] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_0e+1.json b/src/test/resources/test-rom/data/json-parsing/y_number_0e+1.json new file mode 100644 index 000000000..d1d396706 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_0e+1.json @@ -0,0 +1 @@ +[0e+1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_0e1.json b/src/test/resources/test-rom/data/json-parsing/y_number_0e1.json new file mode 100644 index 000000000..3283a7936 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_0e1.json @@ -0,0 +1 @@ +[0e1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_after_space.json b/src/test/resources/test-rom/data/json-parsing/y_number_after_space.json new file mode 100644 index 000000000..623570d96 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_after_space.json @@ -0,0 +1 @@ +[ 4] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_double_close_to_zero.json b/src/test/resources/test-rom/data/json-parsing/y_number_double_close_to_zero.json new file mode 100644 index 000000000..96555ff78 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_double_close_to_zero.json @@ -0,0 +1 @@ +[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_int_with_exp.json b/src/test/resources/test-rom/data/json-parsing/y_number_int_with_exp.json new file mode 100644 index 000000000..a4ca9e754 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_int_with_exp.json @@ -0,0 +1 @@ +[20e1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_minus_zero.json b/src/test/resources/test-rom/data/json-parsing/y_number_minus_zero.json new file mode 100644 index 000000000..37af1312a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_minus_zero.json @@ -0,0 +1 @@ +[-0] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_negative_int.json b/src/test/resources/test-rom/data/json-parsing/y_number_negative_int.json new file mode 100644 index 000000000..8e30f8bd9 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_negative_int.json @@ -0,0 +1 @@ +[-123] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_negative_one.json b/src/test/resources/test-rom/data/json-parsing/y_number_negative_one.json new file mode 100644 index 000000000..99d21a2a0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_negative_one.json @@ -0,0 +1 @@ +[-1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_negative_zero.json b/src/test/resources/test-rom/data/json-parsing/y_number_negative_zero.json new file mode 100644 index 000000000..37af1312a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_negative_zero.json @@ -0,0 +1 @@ +[-0] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e.json new file mode 100644 index 000000000..6edbdfcb1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e.json @@ -0,0 +1 @@ +[1E22] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_neg_exp.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_neg_exp.json new file mode 100644 index 000000000..0a01bd3ef --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_neg_exp.json @@ -0,0 +1 @@ +[1E-2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_pos_exp.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_pos_exp.json new file mode 100644 index 000000000..5a8fc0972 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_pos_exp.json @@ -0,0 +1 @@ +[1E+2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_exponent.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_exponent.json new file mode 100644 index 000000000..da2522d61 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_exponent.json @@ -0,0 +1 @@ +[123e45] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_fraction_exponent.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_fraction_exponent.json new file mode 100644 index 000000000..3944a7a45 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_fraction_exponent.json @@ -0,0 +1 @@ +[123.456e78] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_neg_exp.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_neg_exp.json new file mode 100644 index 000000000..ca40d3c25 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_neg_exp.json @@ -0,0 +1 @@ +[1e-2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_pos_exponent.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_pos_exponent.json new file mode 100644 index 000000000..343601d51 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_pos_exponent.json @@ -0,0 +1 @@ +[1e+2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_simple_int.json b/src/test/resources/test-rom/data/json-parsing/y_number_simple_int.json new file mode 100644 index 000000000..e47f69afc --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_simple_int.json @@ -0,0 +1 @@ +[123] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_simple_real.json b/src/test/resources/test-rom/data/json-parsing/y_number_simple_real.json new file mode 100644 index 000000000..b02878e5f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_simple_real.json @@ -0,0 +1 @@ +[123.456789] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object.json b/src/test/resources/test-rom/data/json-parsing/y_object.json new file mode 100644 index 000000000..78262eda3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object.json @@ -0,0 +1 @@ +{"asd":"sdf", "dfg":"fgh"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_basic.json b/src/test/resources/test-rom/data/json-parsing/y_object_basic.json new file mode 100644 index 000000000..646bbe7bb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_basic.json @@ -0,0 +1 @@ +{"asd":"sdf"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key.json b/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key.json new file mode 100644 index 000000000..bbc2e1ce4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key.json @@ -0,0 +1 @@ +{"a":"b","a":"c"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key_and_value.json b/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key_and_value.json new file mode 100644 index 000000000..211581c20 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key_and_value.json @@ -0,0 +1 @@ +{"a":"b","a":"b"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_empty.json b/src/test/resources/test-rom/data/json-parsing/y_object_empty.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_empty.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_empty_key.json b/src/test/resources/test-rom/data/json-parsing/y_object_empty_key.json new file mode 100644 index 000000000..c0013d3b8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_empty_key.json @@ -0,0 +1 @@ +{"":0} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_escaped_null_in_key.json b/src/test/resources/test-rom/data/json-parsing/y_object_escaped_null_in_key.json new file mode 100644 index 000000000..593f0f67f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_escaped_null_in_key.json @@ -0,0 +1 @@ +{"foo\u0000bar": 42} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_extreme_numbers.json b/src/test/resources/test-rom/data/json-parsing/y_object_extreme_numbers.json new file mode 100644 index 000000000..a0d3531c3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_extreme_numbers.json @@ -0,0 +1 @@ +{ "min": -1.0e+28, "max": 1.0e+28 } \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_long_strings.json b/src/test/resources/test-rom/data/json-parsing/y_object_long_strings.json new file mode 100644 index 000000000..bdc4a0871 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_long_strings.json @@ -0,0 +1 @@ +{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_simple.json b/src/test/resources/test-rom/data/json-parsing/y_object_simple.json new file mode 100644 index 000000000..dacac917f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_simple.json @@ -0,0 +1 @@ +{"a":[]} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_string_unicode.json b/src/test/resources/test-rom/data/json-parsing/y_object_string_unicode.json new file mode 100644 index 000000000..8effdb297 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_string_unicode.json @@ -0,0 +1 @@ +{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_with_newlines.json b/src/test/resources/test-rom/data/json-parsing/y_object_with_newlines.json new file mode 100644 index 000000000..246ec6b34 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_with_newlines.json @@ -0,0 +1,3 @@ +{ +"a": "b" +} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_1_2_3_bytes_UTF-8_sequences.json b/src/test/resources/test-rom/data/json-parsing/y_string_1_2_3_bytes_UTF-8_sequences.json new file mode 100644 index 000000000..9967ddeb8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_1_2_3_bytes_UTF-8_sequences.json @@ -0,0 +1 @@ +["\u0060\u012a\u12AB"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pair.json b/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pair.json new file mode 100644 index 000000000..996875cc8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pair.json @@ -0,0 +1 @@ +["\uD801\udc37"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pairs.json b/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pairs.json new file mode 100644 index 000000000..3401021ec --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pairs.json @@ -0,0 +1 @@ +["\ud83d\ude39\ud83d\udc8d"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_allowed_escapes.json b/src/test/resources/test-rom/data/json-parsing/y_string_allowed_escapes.json new file mode 100644 index 000000000..7f495532f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_allowed_escapes.json @@ -0,0 +1 @@ +["\"\\\/\b\f\n\r\t"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_backslash_and_u_escaped_zero.json b/src/test/resources/test-rom/data/json-parsing/y_string_backslash_and_u_escaped_zero.json new file mode 100644 index 000000000..d4439eda7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_backslash_and_u_escaped_zero.json @@ -0,0 +1 @@ +["\\u0000"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_backslash_doublequotes.json b/src/test/resources/test-rom/data/json-parsing/y_string_backslash_doublequotes.json new file mode 100644 index 000000000..ae03243b6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_backslash_doublequotes.json @@ -0,0 +1 @@ +["\""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_comments.json b/src/test/resources/test-rom/data/json-parsing/y_string_comments.json new file mode 100644 index 000000000..2260c20c2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_comments.json @@ -0,0 +1 @@ +["a/*b*/c/*d//e"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_a.json b/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_a.json new file mode 100644 index 000000000..6715d6f40 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_a.json @@ -0,0 +1 @@ +["\\a"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_n.json b/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_n.json new file mode 100644 index 000000000..44ca56c4d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_n.json @@ -0,0 +1 @@ +["\\n"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_escaped_control_character.json b/src/test/resources/test-rom/data/json-parsing/y_string_escaped_control_character.json new file mode 100644 index 000000000..5b014a9c2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_escaped_control_character.json @@ -0,0 +1 @@ +["\u0012"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_escaped_noncharacter.json b/src/test/resources/test-rom/data/json-parsing/y_string_escaped_noncharacter.json new file mode 100644 index 000000000..2ff52e2c5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_escaped_noncharacter.json @@ -0,0 +1 @@ +["\uFFFF"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_in_array.json b/src/test/resources/test-rom/data/json-parsing/y_string_in_array.json new file mode 100644 index 000000000..21d7ae4cd --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_in_array.json @@ -0,0 +1 @@ +["asd"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_in_array_with_leading_space.json b/src/test/resources/test-rom/data/json-parsing/y_string_in_array_with_leading_space.json new file mode 100644 index 000000000..9e1887c1e --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_in_array_with_leading_space.json @@ -0,0 +1 @@ +[ "asd"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_last_surrogates_1_and_2.json b/src/test/resources/test-rom/data/json-parsing/y_string_last_surrogates_1_and_2.json new file mode 100644 index 000000000..3919cef76 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_last_surrogates_1_and_2.json @@ -0,0 +1 @@ +["\uDBFF\uDFFF"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_nbsp_uescaped.json b/src/test/resources/test-rom/data/json-parsing/y_string_nbsp_uescaped.json new file mode 100644 index 000000000..2085ab1a1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_nbsp_uescaped.json @@ -0,0 +1 @@ +["new\u00A0line"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json b/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json new file mode 100644 index 000000000..059e4d9dd --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json @@ -0,0 +1 @@ +["ô¿¿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+FFFF.json b/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+FFFF.json new file mode 100644 index 000000000..4c913bd41 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+FFFF.json @@ -0,0 +1 @@ +["ï¿¿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_null_escape.json b/src/test/resources/test-rom/data/json-parsing/y_string_null_escape.json new file mode 100644 index 000000000..c1ad84404 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_null_escape.json @@ -0,0 +1 @@ +["\u0000"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_one-byte-utf-8.json b/src/test/resources/test-rom/data/json-parsing/y_string_one-byte-utf-8.json new file mode 100644 index 000000000..157185923 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_one-byte-utf-8.json @@ -0,0 +1 @@ +["\u002c"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_pi.json b/src/test/resources/test-rom/data/json-parsing/y_string_pi.json new file mode 100644 index 000000000..9df11ae88 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_pi.json @@ -0,0 +1 @@ +["Ï€"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json b/src/test/resources/test-rom/data/json-parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json new file mode 100644 index 000000000..10a33a171 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json @@ -0,0 +1 @@ +["𛿿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_simple_ascii.json b/src/test/resources/test-rom/data/json-parsing/y_string_simple_ascii.json new file mode 100644 index 000000000..8cadf7d05 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_simple_ascii.json @@ -0,0 +1 @@ +["asd "] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_space.json b/src/test/resources/test-rom/data/json-parsing/y_string_space.json new file mode 100644 index 000000000..efd782cc3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_space.json @@ -0,0 +1 @@ +" " \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json b/src/test/resources/test-rom/data/json-parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json new file mode 100644 index 000000000..7620b6655 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json @@ -0,0 +1 @@ +["\uD834\uDd1e"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_three-byte-utf-8.json b/src/test/resources/test-rom/data/json-parsing/y_string_three-byte-utf-8.json new file mode 100644 index 000000000..108f1d67d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_three-byte-utf-8.json @@ -0,0 +1 @@ +["\u0821"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_two-byte-utf-8.json b/src/test/resources/test-rom/data/json-parsing/y_string_two-byte-utf-8.json new file mode 100644 index 000000000..461503c31 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_two-byte-utf-8.json @@ -0,0 +1 @@ +["\u0123"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_u+2028_line_sep.json b/src/test/resources/test-rom/data/json-parsing/y_string_u+2028_line_sep.json new file mode 100644 index 000000000..897b6021a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_u+2028_line_sep.json @@ -0,0 +1 @@ +["
"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_u+2029_par_sep.json b/src/test/resources/test-rom/data/json-parsing/y_string_u+2029_par_sep.json new file mode 100644 index 000000000..8cd998c89 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_u+2029_par_sep.json @@ -0,0 +1 @@ +["
"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_uEscape.json b/src/test/resources/test-rom/data/json-parsing/y_string_uEscape.json new file mode 100644 index 000000000..f7b41a02f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_uEscape.json @@ -0,0 +1 @@ +["\u0061\u30af\u30EA\u30b9"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_uescaped_newline.json b/src/test/resources/test-rom/data/json-parsing/y_string_uescaped_newline.json new file mode 100644 index 000000000..3a5a220b6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_uescaped_newline.json @@ -0,0 +1 @@ +["new\u000Aline"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unescaped_char_delete.json b/src/test/resources/test-rom/data/json-parsing/y_string_unescaped_char_delete.json new file mode 100644 index 000000000..7d064f498 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unescaped_char_delete.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode.json new file mode 100644 index 000000000..3598095b7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode.json @@ -0,0 +1 @@ +["\uA66D"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicodeEscapedBackslash.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicodeEscapedBackslash.json new file mode 100644 index 000000000..0bb3b51e7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicodeEscapedBackslash.json @@ -0,0 +1 @@ +["\u005C"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_2.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_2.json new file mode 100644 index 000000000..a7dcb9768 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_2.json @@ -0,0 +1 @@ +["â‚㈴â‚"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+10FFFE_nonchar.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+10FFFE_nonchar.json new file mode 100644 index 000000000..9a8370b96 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+10FFFE_nonchar.json @@ -0,0 +1 @@ +["\uDBFF\uDFFE"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+1FFFE_nonchar.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+1FFFE_nonchar.json new file mode 100644 index 000000000..c51f8ae45 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+1FFFE_nonchar.json @@ -0,0 +1 @@ +["\uD83F\uDFFE"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json new file mode 100644 index 000000000..626d5f815 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json @@ -0,0 +1 @@ +["\u200B"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+2064_invisible_plus.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+2064_invisible_plus.json new file mode 100644 index 000000000..1e23972c6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+2064_invisible_plus.json @@ -0,0 +1 @@ +["\u2064"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FDD0_nonchar.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FDD0_nonchar.json new file mode 100644 index 000000000..18ef151b4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FDD0_nonchar.json @@ -0,0 +1 @@ +["\uFDD0"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FFFE_nonchar.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FFFE_nonchar.json new file mode 100644 index 000000000..13d261fda --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FFFE_nonchar.json @@ -0,0 +1 @@ +["\uFFFE"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_escaped_double_quote.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_escaped_double_quote.json new file mode 100644 index 000000000..4e6257856 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_escaped_double_quote.json @@ -0,0 +1 @@ +["\u0022"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_utf8.json b/src/test/resources/test-rom/data/json-parsing/y_string_utf8.json new file mode 100644 index 000000000..40878435f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_utf8.json @@ -0,0 +1 @@ +["€ð„ž"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_with_del_character.json b/src/test/resources/test-rom/data/json-parsing/y_string_with_del_character.json new file mode 100644 index 000000000..8bd24907d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_with_del_character.json @@ -0,0 +1 @@ +["aa"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_false.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_false.json new file mode 100644 index 000000000..02e4a84d6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_false.json @@ -0,0 +1 @@ +false \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_int.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_int.json new file mode 100644 index 000000000..f70d7bba4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_int.json @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_negative_real.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_negative_real.json new file mode 100644 index 000000000..b5135a207 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_negative_real.json @@ -0,0 +1 @@ +-0.1 \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_null.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_null.json new file mode 100644 index 000000000..ec747fa47 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_null.json @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_string.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_string.json new file mode 100644 index 000000000..b6e982ca9 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_string.json @@ -0,0 +1 @@ +"asd" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_true.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_true.json new file mode 100644 index 000000000..f32a5804e --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_true.json @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_string_empty.json b/src/test/resources/test-rom/data/json-parsing/y_structure_string_empty.json new file mode 100644 index 000000000..3cc762b55 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_string_empty.json @@ -0,0 +1 @@ +"" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_trailing_newline.json b/src/test/resources/test-rom/data/json-parsing/y_structure_trailing_newline.json new file mode 100644 index 000000000..0c3426d4c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_trailing_newline.json @@ -0,0 +1 @@ +["a"] diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_true_in_array.json b/src/test/resources/test-rom/data/json-parsing/y_structure_true_in_array.json new file mode 100644 index 000000000..de601e305 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_true_in_array.json @@ -0,0 +1 @@ +[true] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_whitespace_array.json b/src/test/resources/test-rom/data/json-parsing/y_structure_whitespace_array.json new file mode 100644 index 000000000..2bedf7f2d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_whitespace_array.json @@ -0,0 +1 @@ + [] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_tab_whitespace.json b/src/test/resources/test-rom/data/json-parsing/y_tab_whitespace.json new file mode 100644 index 000000000..d9a9c8b4d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_tab_whitespace.json @@ -0,0 +1 @@ +[ ] diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua new file mode 100644 index 000000000..a5caec7a8 --- /dev/null +++ b/src/test/resources/test-rom/mcfly.lua @@ -0,0 +1,718 @@ +--- A very basic test framework for ComputerCraft +-- +-- Like Busted (http://olivinelabs.com/busted/), but more memorable. +-- +-- @usage +-- describe("something to test", function() +-- it("some property", function() +-- expect(some_function()):equals("What it should equal") +-- end) +-- end) + +--- Assert an argument to the given function has the specified type. +-- +-- @tparam string func The function's name +-- @tparam int idx The argument index to this function +-- @tparam string ty The type this argument should have. May be 'value' for +-- any non-nil value. +-- @param val val The value to check +-- @throws If this value doesn't match the expected type. +local function check(func, idx, ty, val) + if ty == 'value' then + if val == nil then + error(('%s: bad argument #%d (got nil)'):format(func, idx), 3) + end + elseif type(val) ~= ty then + return error(('%s: bad argument #%d (expected %s, got %s)'):format(func, idx, ty, type(val)), 3) + end +end + +--- A stub - wraps a value within a a table, +local stub_mt = {} +stub_mt.__index = stub_mt + +--- Revert this stub, restoring the previous value. +-- +-- Note, a stub can only be reverted once. +function stub_mt:revert() + if not self.active then return end + + self.active = false + rawset(self.stubbed_in, self.key, self.original) +end + +local active_stubs = {} + +local function default_stub() end + +--- Stub a table entry with a new value. +-- +-- @tparam table tbl The table whose field should be stubbed. +-- @tparam string key The variable to stub +-- @param[opt] value The value to stub it with. If this is a function, one can +-- use the various stub expectation methods to determine what it was called +-- with. Defaults to an empty function - pass @{nil} in explicitly to set the +-- value to nil. +-- @treturn Stub The resulting stub +local function stub(tbl, key, ...) + check('stub', 1, 'table', tbl) + check('stub', 2, 'string', key) + + local stub = setmetatable({ + active = true, + stubbed_in = tbl, + key = key, + original = rawget(tbl, key), + }, stub_mt) + + local value = ... + if select('#', ...) == 0 then value = default_stub end + if type(value) == "function" then + local arguments, delegate = {}, value + stub.arguments = arguments + value = function(...) + arguments[#arguments + 1] = table.pack(...) + return delegate(...) + end + end + + table.insert(active_stubs, stub) + rawset(tbl, key, value) + return stub +end + +--- Capture the current global state of the computer +local function push_state() + local stubs = active_stubs + active_stubs = {} + return { + term = term.current(), + input = io.input(), + output = io.output(), + dir = shell.dir(), + path = shell.path(), + aliases = shell.aliases(), + stubs = stubs, + } +end + +--- Restore the global state of the computer to a previous version +local function pop_state(state) + for i = #active_stubs, 1, -1 do active_stubs[i]:revert() end + + active_stubs = state.stubs + + term.redirect(state.term) + io.input(state.input) + io.output(state.output) + shell.setDir(state.dir) + shell.setPath(state.path) + + local aliases = shell.aliases() + for k in pairs(aliases) do + if not state.aliases[k] then shell.clearAlias(k) end + end + for k, v in pairs(state.aliases) do + if aliases[k] ~= v then shell.setAlias(k, v) end + end +end + +local error_mt = { __tostring = function(self) return self.message end } + +--- Attempt to execute the provided function, gathering a stack trace when it +-- errors. +-- +-- @tparam function() fn The function to run +-- @return[1] true +-- @return[2] false +-- @return[2] The error object +local function try(fn) + if not debug or not debug.traceback then + local ok, err = pcall(fn) + if ok or getmetatable(err) == error_mt then + return ok, err + else + return ok, setmetatable({ message = tostring(err) }, error_mt) + end + end + + local ok, err = xpcall(fn, function(err) + return { message = err, trace = debug.traceback(nil, 2) } + end) + + -- If we succeeded, propagate it + if ok then return ok, err end + + -- Error handling failed for some reason - just return a simpler error + if type(err) ~= "table" then + return ok, setmetatable({ message = tostring(err) }, error_mt) + end + + -- Find the common substring the errors' trace and the current one. Then + -- eliminate it. + local trace = debug.traceback() + for i = 1, #trace do + if trace:sub(-i) ~= err.trace:sub(-i) then + err.trace = err.trace:sub(1, -i) + break + end + end + + -- If we've received a rethrown error, copy + if getmetatable(err.message) == error_mt then + for k, v in pairs(err.message) do err[k] = v end + return ok, err + end + + return ok, setmetatable(err, error_mt) +end + +--- Fail a test with the given message +-- +-- @tparam string message The message to fail with +-- @throws An error with the given message +local function fail(message) + check('fail', 1, 'string', message) + error(setmetatable({ message = message, fail = true }, error_mt)) +end + +--- Format an object in order to make it more readable +-- +-- @param value The value to format +-- @treturn string The formatted value +local function format(value) + -- TODO: Look into something like mbs's pretty printer. + local ok, res = pcall(textutils.serialise, value) + if ok then return res else return tostring(value) end +end + +local expect_mt = {} +expect_mt.__index = expect_mt + +function expect_mt:_fail(message) + if self._extra then message = self._extra .. "\n" .. message end + fail(message) +end + +--- Assert that this expectation has the provided value +-- +-- @param value The value to require this expectation to be equal to +-- @throws If the values are not equal +function expect_mt:equals(value) + if value ~= self.value then + self:_fail(("Expected %s\n but got %s"):format(format(value), format(self.value))) + end + + return self +end +expect_mt.equal = expect_mt.equals +expect_mt.eq = expect_mt.equals + +--- Assert that this expectation does not equal the provided value +-- +-- @param value The value to require this expectation to not be equal to +-- @throws If the values are equal +function expect_mt:not_equals(value) + if value == self.value then + self:_fail(("Expected any value but %s"):format(format(value))) + end + + return self +end +expect_mt.not_equal = expect_mt.not_equals +expect_mt.ne = expect_mt.not_equals + +--- Assert that this expectation has something of the provided type +-- +-- @tparam string exp_type The type to require this expectation to have +-- @throws If it does not have that thpe +function expect_mt:type(exp_type) + local actual_type = type(self.value) + if exp_type ~= actual_type then + self:_fail(("Expected value of type %s\nbut got %s"):format(exp_type, actual_type)) + end + + return self +end + +local function matches(eq, exact, left, right) + if left == right then return true end + + local ty = type(left) + if ty ~= type(right) or ty ~= "table" then return false end + + -- If we've already explored/are exploring the left and right then return + if eq[left] and eq[left][right] then return true end + if not eq[left] then eq[left] = { [right] = true } else eq[left][right] = true end + if not eq[right] then eq[right] = { [left] = true } else eq[right][left] = true end + + -- Verify all pairs in left are equal to those in right + for k, v in pairs(left) do + if not matches(eq, exact, v, right[k]) then return false end + end + + if exact then + -- And verify all pairs in right are present in left + for k in pairs(right) do + if left[k] == nil then return false end + end + end + + return true +end + +local function pairwise_equal(left, right) + if left.n ~= right.n then return false end + + for i = 1, left.n do + if left[i] ~= right[i] then return false end + end + + return true +end + +--- Assert that this expectation is structurally equivalent to +-- the provided object. +-- +-- @param value The value to check for structural equivalence +-- @throws If they are not equivalent +function expect_mt:same(value) + if not matches({}, true, self.value, value) then + self:_fail(("Expected %s\nbut got %s"):format(format(value), format(self.value))) + end + + return self +end + +--- Assert that this expectation contains all fields mentioned +-- in the provided object. +-- +-- @param value The value to check against +-- @throws If this does not match the provided value +function expect_mt:matches(value) + if not matches({}, false, value, self.value) then + self:_fail(("Expected %s\nto match %s"):format(format(self.value), format(value))) + end + + return self +end + +--- Assert that this stub was called a specific number of times. +-- +-- @tparam[opt] number The exact number of times the function must be called. +-- If not given just require the function to be called at least once. +-- @throws If this function was not called the expected number of times. +function expect_mt:called(times) + if getmetatable(self.value) ~= stub_mt or self.value.arguments == nil then + self:_fail(("Expected stubbed function, got %s"):format(type(self.value))) + end + + local called = #self.value.arguments + + if times == nil then + if called == 0 then + self:_fail("Expected stub to be called\nbut it was not.") + end + else + check('stub', 1, 'number', times) + if called ~= times then + self:_fail(("Expected stub to be called %d times\nbut was called %d times."):format(times, called)) + end + end + + return self +end + +local function called_with_check(eq, self, ...) + if getmetatable(self.value) ~= stub_mt or self.value.arguments == nil then + self:_fail(("Expected stubbed function, got %s"):format(type(self.value))) + end + + local exp_args = table.pack(...) + local actual_args = self.value.arguments + for i = 1, #actual_args do + if eq(actual_args[i], exp_args) then return self end + end + + local head = ("Expected stub to be called with %s\nbut was"):format(format(exp_args)) + if #actual_args == 0 then + self:_fail(head .. " not called at all") + elseif #actual_args == 1 then + self:_fail(("%s called with %s."):format(head, format(actual_args[1]))) + else + local lines = { head .. " called with:" } + for i = 1, #actual_args do lines[i + 1] = " - " .. format(actual_args[i]) end + + self:_fail(table.concat(lines, "\n")) + end +end + +--- Assert that this stub was called with a set of arguments +-- +-- Arguments are compared using exact equality. +function expect_mt:called_with(...) + return called_with_check(pairwise_equal, self, ...) +end + +--- Assert that this stub was called with a set of arguments +-- +-- Arguments are compared using matching. +function expect_mt:called_with_matching(...) + return called_with_check(matches, self, ...) +end + +--- Assert that this expectation matches a Lua pattern +-- +-- @tparam string pattern The pattern to match against +-- @throws If it does not match this pattern. +function expect_mt:str_match(pattern) + local actual_type = type(self.value) + if actual_type ~= "string" then + self:_fail(("Expected value of type string\nbut got %s"):format(actual_type)) + end + if not self.value:find(pattern) then + self:_fail(("Expected %q\n to match pattern %q"):format(self.value, pattern)) + end + + return self +end + +--- Add extra information to this error message. +-- +-- @tparam string message Additional message to prepend in the case of failures. +-- @return The current +function expect_mt:describe(message) + self._extra = tostring(message) + return self +end + +local expect = {} +setmetatable(expect, expect) + +--- Construct an expectation on the error message calling this function +-- produces +-- +-- @tparam fun The function to call +-- @param ... The function arguments +-- @return The new expectation +function expect.error(fun, ...) + local ok, res = pcall(fun, ...) local _, line = pcall(error, "", 2) + if ok then fail("expected function to error") end + if res:sub(1, #line) == line then + res = res:sub(#line + 1) + elseif res:sub(1, 7) == "pcall: " then + res = res:sub(8) + end + return setmetatable({ value = res }, expect_mt) +end + +--- Construct a new expectation from the provided value +-- +-- @param value The value to apply assertions to +-- @return The new expectation +function expect:__call(value) + return setmetatable({ value = value }, expect_mt) +end + +--- The stack of "describe"s. +local test_stack = { n = 0 } + +--- Whether we're now running tests, and so cannot run any more. +local tests_locked = false + +--- The list of tests that we'll run +local test_list = {} +local test_map, test_count = {}, 0 + +--- Add a new test to our queue. +-- +-- @param test The descriptor of this test +local function do_test(test) + -- Set the name if it doesn't already exist + if not test.name then test.name = table.concat(test_stack, "\0", 1, test_stack.n) end + test_count = test_count + 1 + test_list[test_count] = test + test_map[test.name] = test_count +end + +--- Get the "friendly" name of this test. +-- +-- @treturn string This test's friendly name +local function test_name(test) return (test.name:gsub("\0", " \26 ")) end + +--- Describe something which will be tested, such as a function or situation +-- +-- @tparam string name The name of the object to test +-- @tparam function body A function which describes the tests for this object. +local function describe(name, body) + check('describe', 1, 'string', name) + check('describe', 2, 'function', body) + if tests_locked then error("Cannot describe something while running tests", 2) end + + -- Push our name onto the stack, eval and pop it + local n = test_stack.n + 1 + test_stack[n], test_stack.n = name, n + + local ok, err = try(body) + + -- We count errors as a (failing) test. + if not ok then do_test { error = err } end + + test_stack.n = n - 1 +end + +--- Declare a single test within a context +-- +-- @tparam string name What you are testing +-- @tparam function body A function which runs the test, failing if it does +-- the assertions are not met. +local function it(name, body) + check('it', 1, 'string', name) + check('it', 2, 'function', body) + if tests_locked then error("Cannot create test while running tests", 2) end + + -- Push name onto the stack + local n = test_stack.n + 1 + test_stack[n], test_stack.n, tests_locked = name, n, true + + do_test { action = body } + + -- Pop the test from the stack + test_stack.n, tests_locked = n - 1, false +end + +--- Declare a single not-yet-implemented test +-- +-- @tparam string name What you really should be testing but aren't +local function pending(name) + check('it', 1, 'string', name) + if tests_locked then error("Cannot create test while running tests", 2) end + + local _, loc = pcall(error, "", 3) + loc = loc:gsub(":%s*$", "") + + local n = test_stack.n + 1 + test_stack[n], test_stack.n = name, n + do_test { pending = true, trace = loc } + test_stack.n = n - 1 +end + +local native_co_create, native_loadfile = coroutine.create, loadfile +local line_counts = {} +if cct_test then + local string_sub, debug_getinfo = string.sub, debug.getinfo + local function debug_hook(_, line_nr) + local name = debug_getinfo(2, "S").source + if string_sub(name, 1, 1) ~= "@" then return end + name = string_sub(name, 2) + + local file = line_counts[name] + if not file then file = {} line_counts[name] = file end + file[line_nr] = (file[line_nr] or 0) + 1 + end + + coroutine.create = function(...) + local co = native_co_create(...) + debug.sethook(co, debug_hook, "l") + return co + end + + local expect = require "cc.expect".expect + _G.native_loadfile = native_loadfile + _G.loadfile = function(filename, mode, env) + -- Support the previous `loadfile(filename, env)` form instead. + if type(mode) == "table" and env == nil then + mode, env = nil, mode + end + + expect(1, filename, "string") + expect(2, mode, "string", "nil") + expect(3, env, "table", "nil") + + local file = fs.open(filename, "r") + if not file then return nil, "File not found" end + + local func, err = load(file.readAll(), "@/" .. fs.combine(filename, ""), mode, env) + file.close() + return func, err + end + + debug.sethook(debug_hook, "l") +end + +local arg = ... +if arg == "--help" or arg == "-h" then + io.write("Usage: mcfly [DIR]\n") + io.write("\n") + io.write("Run tests in the provided DIRectory, or `spec` if not given.") + return +end + +local root_dir = shell.resolve(arg or "spec") +if not fs.isDir(root_dir) then + io.stderr:write(("%q is not a directory.\n"):format(root_dir)) + error() +end + +-- Ensure the test folder is also on the package path +package.path = ("/%s/?.lua;/%s/?/init.lua;%s"):format(root_dir, root_dir, package.path) + +do + -- Load in the tests from all our files + local env = setmetatable({}, { __index = _ENV }) + + local function set_env(tbl) + for k in pairs(env) do env[k] = nil end + for k, v in pairs(tbl) do env[k] = v end + end + + -- When declaring tests, you shouldn't be able to use test methods + set_env { describe = describe, it = it, pending = pending } + + local suffix = "_spec.lua" + local function run_in(sub_dir) + for _, name in ipairs(fs.list(sub_dir)) do + local file = fs.combine(sub_dir, name) + if fs.isDir(file) then + run_in(file) + elseif file:sub(-#suffix) == suffix then + local fun, err = loadfile(file, nil, env) + if not fun then + do_test { name = file:sub(#root_dir + 2), error = { message = err } } + else + local ok, err = try(fun) + if not ok then do_test { name = file:sub(#root_dir + 2), error = err } end + end + end + end + end + + run_in(root_dir) + + -- When running tests, you shouldn't be able to declare new ones. + set_env { expect = expect, fail = fail, stub = stub } +end + +-- Error if we've found no tests +if test_count == 0 then + io.stderr:write(("Could not find any tests in %q\n"):format(root_dir)) + error() +end + +-- The results of each test, as well as how many passed and the count. +local test_results, test_status, tests_run = { n = 0 }, {}, 0 + +-- All possible test statuses +local statuses = { + pass = { desc = "Pass", col = colours.green, dot = "\7" }, -- Circle + fail = { desc = "Failed", col = colours.red, dot = "\4" }, -- Diamond + error = { desc = "Error", col = colours.magenta, dot = "\4" }, + pending = { desc = "Pending", col = colours.yellow, dot = "\186" }, -- Hollow circle +} + +-- Set up each test status count. +for k in pairs(statuses) do test_status[k] = 0 end + +--- Do the actual running of our test +local function do_run(test) + -- If we're a pre-computed test, determine our status message. Otherwise, + -- skip. + local status, err + if test.pending then + status = "pending" + elseif test.error then + err = test.error + status = "error" + elseif test.action then + local state = push_state() + + -- Flush the event queue and ensure we're running with 0 timeout. + os.queueEvent("start_test") os.pullEvent("start_test") + + local ok + ok, err = try(test.action) + status = ok and "pass" or (err.fail and "fail" or "error") + + pop_state(state) + end + + -- If we've a boolean status, then convert it into a string + if status == true then status = "pass" + elseif status == false then status = err.fail and "fail" or "error" + end + + tests_run = tests_run + 1 + test_status[status] = test_status[status] + 1 + test_results[tests_run] = { + status = status, name = test.name, + message = test.message or err and err.message, + trace = test.trace or err and err.trace, + } + + -- If we're running under howlci, then log some info. + if howlci then howlci.status(status, test_name(test)) end + if cct_test then cct_test.submit(test_results[tests_run]) end + + -- Print our progress dot + local data = statuses[status] + term.setTextColour(data.col) io.write(data.dot) + term.setTextColour(colours.white) +end + +-- Loop over all our tests, running them as required. +if cct_test then + -- If we're within a cct_test environment, then submit them and wait on tests + -- to be run. + cct_test.start(test_map) + while true do + local _, name = os.pullEvent("cct_test_run") + if not name then break end + do_run(test_list[test_map[name]]) + end +else + for _, test in pairs(test_list) do do_run(test) end +end + +-- Otherwise, display the results of each failure +io.write("\n\n") +for i = 1, tests_run do + local test = test_results[i] + if test.status ~= "pass" then + local status_data = statuses[test.status] + + term.setTextColour(status_data.col) + io.write(status_data.desc) + term.setTextColour(colours.white) + io.write(" \26 " .. test_name(test) .. "\n") + + if test.message then + io.write(" " .. test.message:gsub("\n", "\n ") .. "\n") + end + + if test.trace then + term.setTextColour(colours.lightGrey) + io.write(" " .. test.trace:gsub("\n", "\n ") .. "\n") + end + + io.write("\n") + end +end + +-- And some summary statistics +local actual_count = tests_run - test_status.pending +local info = ("Ran %s test(s), of which %s passed (%g%%).") + :format(actual_count, test_status.pass, test_status.pass / actual_count * 100) + +if test_status.pending > 0 then + info = info .. (" Skipped %d pending test(s)."):format(test_status.pending) +end + +term.setTextColour(colours.white) io.write(info .. "\n") + +-- Restore hook stubs +debug.sethook(nil, "l") +coroutine.create = native_co_create +_G.loadfile = native_loadfile + +if cct_test then cct_test.finish(line_counts) end +if howlci then howlci.log("debug", info) sleep(3) end diff --git a/src/test/resources/test-rom/spec/apis/colors_spec.lua b/src/test/resources/test-rom/spec/apis/colors_spec.lua new file mode 100644 index 000000000..c7505ca5a --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/colors_spec.lua @@ -0,0 +1,92 @@ +describe("The colors library", function() + describe("colors.combine", function() + it("validates arguments", function() + expect.error(colors.combine, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(colors.combine, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + end) + + it("combines colours", function() + expect(colors.combine()):eq(0) + expect(colors.combine(colors.red, colors.brown, colors.green)):eq(0x7000) + end) + end) + + describe("colors.subtract", function() + it("validates arguments", function() + expect.error(colors.subtract, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(colors.subtract, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(colors.subtract, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + end) + + it("subtracts colours", function() + expect(colors.subtract(0x7000, colors.green)):equals(0x5000) + expect(colors.subtract(0x5000, colors.red)):equals(0x1000) + end) + it("does nothing when color is not present", function() + expect(colors.subtract(0x1000, colors.red)):equals(0x1000) + end) + it("accepts multiple arguments", function() + expect(colors.subtract(0x7000, colors.red, colors.green, colors.red)):equals(0x1000) + end) + end) + + describe("colors.test", function() + it("validates arguments", function() + expect.error(colors.test, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(colors.test, 1, nil):eq("bad argument #2 (expected number, got nil)") + end) + + it("returns true when present", function() + expect(colors.test(0x7000, colors.green)):equals(true) + end) + it("returns false when absent", function() + expect(colors.test(0x5000, colors.green)):equals(false) + end) + it("allows multiple colors", function() + expect(colors.test(0x7000, 0x5000)):equals(true) + end) + end) + + describe("colors.packRGB", function() + it("validates arguments", function() + expect.error(colors.packRGB, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(colors.packRGB, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(colors.packRGB, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + end) + + it("packs colours", function() + expect(colors.packRGB(0.3, 0.5, 0.6)):equals(0x4c7f99) + end) + end) + + describe("colors.unpackRGB", function() + it("validates arguments", function() + expect.error(colors.unpackRGB, nil):eq("bad argument #1 (expected number, got nil)") + end) + + it("unpacks colours", function() + expect({ colors.unpackRGB(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 } + end) + end) + + it("colors.rgb8", function() + expect(colors.rgb8(0.3, 0.5, 0.6)):equals(0x4c7f99) + expect({ colors.rgb8(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 } + end) + + describe("colors.toBlit", function() + it("validates arguments", function() + expect.error(colors.toBlit, nil):eq("bad argument #1 (expected number, got nil)") + end) + + it("converts all colors", function() + for i = 0, 15 do + expect(colors.toBlit(2 ^ i)):eq(string.format("%x", i)) + end + end) + + it("floors colors", function() + expect(colors.toBlit(16385)):eq("e") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua new file mode 100644 index 000000000..32503598e --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -0,0 +1,222 @@ +describe("The fs library", function() + describe("fs.complete", function() + it("validates arguments", function() + fs.complete("", "") + fs.complete("", "", true) + fs.complete("", "", nil, true) + + expect.error(fs.complete, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(fs.complete, "", nil):eq("bad argument #2 (expected string, got nil)") + expect.error(fs.complete, "", "", 1):eq("bad argument #3 (expected boolean, got number)") + expect.error(fs.complete, "", "", true, 1):eq("bad argument #4 (expected boolean, got number)") + end) + end) + + describe("fs.isDriveRoot", function() + it("validates arguments", function() + fs.isDriveRoot("") + + expect.error(fs.isDriveRoot, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("correctly identifies drive roots", function() + expect(fs.isDriveRoot("/rom")):eq(true) + expect(fs.isDriveRoot("/")):eq(true) + expect(fs.isDriveRoot("/rom/startup.lua")):eq(false) + expect(fs.isDriveRoot("/rom/programs/delete.lua")):eq(false) + end) + end) + + describe("fs.list", function() + it("fails on files", function() + expect.error(fs.list, "rom/startup.lua"):eq("/rom/startup.lua: Not a directory") + expect.error(fs.list, "startup.lua"):eq("/startup.lua: Not a directory") + end) + + it("fails on non-existent nodes", function() + expect.error(fs.list, "rom/x"):eq("/rom/x: Not a directory") + expect.error(fs.list, "x"):eq("/x: Not a directory") + end) + end) + + describe("fs.combine", function() + it("removes . and ..", function() + expect(fs.combine("./a/b")):eq("a/b") + expect(fs.combine("a/b", "../c")):eq("a/c") + expect(fs.combine("a", "../c")):eq("c") + expect(fs.combine("a", "../../c")):eq("../c") + end) + + it("combines empty paths", function() + expect(fs.combine("a")):eq("a") + expect(fs.combine("a", "")):eq("a") + expect(fs.combine("", "a")):eq("a") + expect(fs.combine("a", "", "b", "c")):eq("a/b/c") + end) + end) + + describe("fs.getSize", function() + it("fails on non-existent nodes", function() + expect.error(fs.getSize, "rom/x"):eq("/rom/x: No such file") + expect.error(fs.getSize, "x"):eq("/x: No such file") + end) + end) + + describe("fs.open", function() + describe("reading", function() + it("fails on directories", function() + expect { fs.open("rom", "r") }:same { nil, "/rom: No such file" } + expect { fs.open("", "r") }:same { nil, "/: No such file" } + end) + + it("fails on non-existent nodes", function() + expect { fs.open("rom/x", "r") }:same { nil, "/rom/x: No such file" } + expect { fs.open("x", "r") }:same { nil, "/x: No such file" } + end) + + it("errors when closing twice", function() + local handle = fs.open("rom/startup.lua", "r") + handle.close() + expect.error(handle.close):eq("attempt to use a closed file") + end) + end) + + describe("reading in binary mode", function() + it("errors when closing twice", function() + local handle = fs.open("rom/startup.lua", "rb") + handle.close() + expect.error(handle.close):eq("attempt to use a closed file") + end) + end) + + describe("writing", function() + it("fails on directories", function() + expect { fs.open("", "w") }:same { nil, "/: Cannot write to directory" } + end) + + it("fails on read-only mounts", function() + expect { fs.open("rom/x", "w") }:same { nil, "/rom/x: Access denied" } + end) + + it("errors when closing twice", function() + local handle = fs.open("test-files/out.txt", "w") + handle.close() + expect.error(handle.close):eq("attempt to use a closed file") + end) + + it("fails gracefully when opening 'CON' on Windows", function() + local ok, err = fs.open("test-files/con", "w") + if ok then fs.delete("test-files/con") return end + + -- On my Windows/Java version the message appears to be "Incorrect function.". It may not be + -- consistent though, and honestly doesn't matter too much. + expect(err):str_match("^/test%-files/con: .*") + end) + end) + + describe("writing in binary mode", function() + it("errors when closing twice", function() + local handle = fs.open("test-files/out.txt", "wb") + handle.close() + expect.error(handle.close):eq("attempt to use a closed file") + end) + end) + + describe("appending", function() + it("fails on directories", function() + expect { fs.open("", "a") }:same { nil, "/: Cannot write to directory" } + end) + + it("fails on read-only mounts", function() + expect { fs.open("rom/x", "a") }:same { nil, "/rom/x: Access denied" } + end) + end) + end) + + describe("fs.makeDir", function() + it("fails on files", function() + expect.error(fs.makeDir, "startup.lua"):eq("/startup.lua: File exists") + end) + + it("fails on read-only mounts", function() + expect.error(fs.makeDir, "rom/x"):eq("/rom/x: Access denied") + end) + end) + + describe("fs.delete", function() + it("fails on read-only mounts", function() + expect.error(fs.delete, "rom/x"):eq("/rom/x: Access denied") + end) + end) + + describe("fs.copy", function() + it("fails on read-only mounts", function() + expect.error(fs.copy, "rom", "rom/startup"):eq("/rom/startup: Access denied") + end) + + it("fails to copy a folder inside itself", function() + fs.makeDir("some-folder") + expect.error(fs.copy, "some-folder", "some-folder/x"):eq("/some-folder: Can't copy a directory inside itself") + expect.error(fs.copy, "some-folder", "Some-Folder/x"):eq("/some-folder: Can't copy a directory inside itself") + end) + + it("copies folders", function() + fs.delete("some-folder") + fs.delete("another-folder") + + fs.makeDir("some-folder") + fs.copy("some-folder", "another-folder") + expect(fs.isDir("another-folder")):eq(true) + end) + end) + + describe("fs.move", function() + it("fails on read-only mounts", function() + expect.error(fs.move, "rom", "rom/move"):eq("Access denied") + expect.error(fs.move, "test-files", "rom/move"):eq("Access denied") + expect.error(fs.move, "rom", "test-files"):eq("Access denied") + end) + end) + + describe("fs.getCapacity", function() + it("returns nil on read-only mounts", function() + expect(fs.getCapacity("rom")):eq(nil) + end) + + it("returns the capacity on the root mount", function() + expect(fs.getCapacity("")):eq(10000000) + end) + end) + + describe("fs.attributes", function() + it("errors on non-existent files", function() + expect.error(fs.attributes, "xuxu_nao_existe"):eq("/xuxu_nao_existe: No such file") + end) + + it("returns information about read-only mounts", function() + expect(fs.attributes("rom")):matches { isDir = true, size = 0, isReadOnly = true } + end) + + it("returns information about files", function() + local now = os.epoch("utc") + + fs.delete("/tmp/basic-file") + local h = fs.open("/tmp/basic-file", "w") + h.write("A reasonably sized string") + h.close() + + local attributes = fs.attributes("tmp/basic-file") + expect(attributes):matches { isDir = false, size = 25, isReadOnly = false } + + if attributes.created - now >= 1000 then + fail(("Expected created time (%d) to be within 1000ms of now (%d"):format(attributes.created, now)) + end + + if attributes.modified - now >= 1000 then + fail(("Expected modified time (%d) to be within 1000ms of now (%d"):format(attributes.modified, now)) + end + + expect(attributes.modification):eq(attributes.modified) + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/gps_spec.lua b/src/test/resources/test-rom/spec/apis/gps_spec.lua new file mode 100644 index 000000000..1e0a49f87 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/gps_spec.lua @@ -0,0 +1,15 @@ +describe("The gps library", function() + describe("gps.locate", function() + it("validates arguments", function() + stub(_G, "commands", { getBlockPosition = function() + end, }) + + gps.locate() + gps.locate(1) + gps.locate(1, true) + + expect.error(gps.locate, ""):eq("bad argument #1 (expected number, got string)") + expect.error(gps.locate, 1, ""):eq("bad argument #2 (expected boolean, got string)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/help_spec.lua b/src/test/resources/test-rom/spec/apis/help_spec.lua new file mode 100644 index 000000000..f8ebcdb5c --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/help_spec.lua @@ -0,0 +1,27 @@ +describe("The help library", function() + describe("help.setPath", function() + it("validates arguments", function() + help.setPath(help.path()) + expect.error(help.setPath, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("help.lookup", function() + it("validates arguments", function() + help.lookup("") + expect.error(help.lookup, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("help.completeTopic", function() + it("validates arguments", function() + help.completeTopic("") + expect.error(help.completeTopic, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("completes topics without extensions", function() + expect(help.completeTopic("changel")):same { "og" } + expect(help.completeTopic("turt")):same { "le" } + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/http_spec.lua b/src/test/resources/test-rom/spec/apis/http_spec.lua new file mode 100644 index 000000000..4a6a8b803 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/http_spec.lua @@ -0,0 +1,21 @@ +describe("The http library", function() + describe("http.checkURL", function() + it("accepts well formed domains", function() + expect({ http.checkURL("https://google.com") }):same({ true }) + end) + + it("rejects malformed URLs", function() + expect({ http.checkURL("google.com") }):same({ false, "Must specify http or https" }) + expect({ http.checkURL("https:google.com") }):same({ false, "URL malformed" }) + expect({ http.checkURL("https:/google.com") }):same({ false, "URL malformed" }) + expect({ http.checkURL("wss://google.com") }):same({ false, "Invalid protocol 'wss'" }) + end) + + it("rejects local domains", function() + -- Note, this is tested more thoroughly in AddressRuleTest. We've just got this here + -- to ensure the general control flow works. + expect({ http.checkURL("http://localhost") }):same({ false, "Domain not permitted" }) + expect({ http.checkURL("http://127.0.0.1") }):same({ false, "Domain not permitted" }) + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/io_spec.lua b/src/test/resources/test-rom/spec/apis/io_spec.lua new file mode 100644 index 000000000..b1746093f --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/io_spec.lua @@ -0,0 +1,328 @@ +--- Tests the io library is (mostly) consistent with PUC Lua. +-- +-- These tests are based on the tests for Lua 5.1 and 5.3 + +describe("The io library", function() + local file = "/test-files/tmp.txt" + local otherfile = "/test-files/tmp2.txt" + + local t = '0123456789' + for _ = 1, 12 do t = t .. t end + assert(#t == 10 * 2 ^ 12) + + local function read_all(f) + local h = fs.open(f, "rb") + local contents = h.readAll() + h.close() + return contents + end + + local function write_file(f, contents) + local h = fs.open(f, "wb") + h.write(contents) + h.close() + end + + local function setup() + write_file(file, "\"�lo\"{a}\nsecond line\nthird line \n�fourth_line\n\n\9\9 3450\n") + end + + describe("io.close", function() + it("cannot close stdin", function() + expect{ io.stdin:close() }:same { nil, "attempt to close standard stream" } + end) + it("cannot close stdout", function() + expect{ io.stdout:close() }:same { nil, "attempt to close standard stream" } + end) + it("cannot close stdout", function() + expect{ io.stdout:close() }:same { nil, "attempt to close standard stream" } + end) + end) + + it("io.input on a handle returns that handle", function() + expect(io.input(io.stdin)):equals(io.stdin) + end) + + it("io.output on a handle returns that handle", function() + expect(io.output(io.stdout)):equals(io.stdout) + end) + + it("defines a __name field", function() + expect(getmetatable(io.input()).__name):eq("FILE*") + end) + + describe("io.type", function() + it("returns file on handles", function() + local handle = io.input() + expect(handle):type("table") + expect(io.type(handle)):equals("file") + expect(io.type(io.stdin)):equals("file") + end) + + it("returns nil on values", function() + expect(io.type(8)):equals(nil) + end) + + it("returns nil on tables", function() + expect(io.type(setmetatable({}, {}))):equals(nil) + end) + end) + + describe("io.lines", function() + it("validates arguments", function() + io.lines(nil) + expect.error(io.lines, ""):eq("/: No such file") + expect.error(io.lines, false):eq("bad argument #1 (expected string, got boolean)") + end) + + it("closes the file", function() + setup() + + local n = 0 + local f = io.lines(file) + while f() do n = n + 1 end + expect(n):eq(6) + + expect.error(f):eq("file is already closed") + expect.error(f):eq("file is already closed") + end) + + it("can copy a file", function() + setup() + + local n = 0 + io.output(otherfile) + for l in io.lines(file) do + io.write(l, "\n") + n = n + 1 + end + io.close() + expect(n):eq(6) + + io.input(file) + local f = io.open(otherfile):lines() + local n = 0 + for l in io.lines() do + expect(l):eq(f()) + n = n + 1 + end + expect(n):eq(6) + end) + + it("does not close on a normal file handle", function() + setup() + + local f = assert(io.open(file)) + local n = 0 + for _ in f:lines() do n = n + 1 end + expect(n):eq(6) + + expect(tostring(f):sub(1, 5)):eq("file ") + assert(f:close()) + + expect(tostring(f)):eq("file (closed)") + expect(io.type(f)):eq("closed file") + end) + + it("accepts multiple arguments", function() + write_file(file, "0123456789\n") + for a, b in io.lines(file, 1, 1) do + if a == "\n" then + expect(b):eq(nil) + else + expect(tonumber(a)):eq(tonumber(b) - 1) + end + end + + for a, b, c in io.lines(file, 1, 2, "a") do + expect(a):eq("0") + expect(b):eq("12") + expect(c):eq("3456789\n") + end + + for a, b, c in io.lines(file, "a", 0, 1) do + if a == "" then break end + expect(a):eq("0123456789\n") + expect(b):eq(nil) + expect(c):eq(nil) + end + + write_file(file, "00\n10\n20\n30\n40\n") + for a, b in io.lines(file, "n", "n") do + if a == 40 then + expect(b):eq(nil) + else + expect(a):eq(b - 10) + end + end + end) + end) + + describe("io.open", function() + it("validates arguments", function() + io.open("") + io.open("", "r") + + expect.error(io.open, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(io.open, "", false):eq("bad argument #2 (expected string, got boolean)") + end) + + it("checks the mode", function() + io.open(file, "w"):close() + + -- This really should be invalid mode, but I'll live. + expect.error(io.open, file, "rw"):str_match("Unsupported mode") + -- TODO: expect.error(io.open, file, "rb+"):str_match("Unsupported mode") + expect.error(io.open, file, "r+bk"):str_match("Unsupported mode") + expect.error(io.open, file, ""):str_match("Unsupported mode") + expect.error(io.open, file, "+"):str_match("Unsupported mode") + expect.error(io.open, file, "b"):str_match("Unsupported mode") + + assert(io.open(file, "r+b")):close() + assert(io.open(file, "r+")):close() + assert(io.open(file, "rb")):close() + end) + + it("returns an error message on non-existent files", function() + local a, b = io.open('xuxu_nao_existe') + expect(a):equals(nil) + expect(b):type("string") + end) + end) + + describe("a readable handle", function() + it("cannot be written to", function() + write_file(file, "") + io.input(file) + expect { io.input():write("xuxu") }:same { nil, "file is not writable" } + io.input(io.stdin) + end) + + it("supports various modes", function() + write_file(file, "alo\n " .. t .. " ;end of file\n") + + io.input(file) + expect(io.read()):eq("alo") + expect(io.read(1)):eq(' ') + expect(io.read(#t)):eq(t) + expect(io.read(1)):eq(' ') + expect(io.read(0)) + expect(io.read('*a')):eq(';end of file\n') + expect(io.read(0)):eq(nil) + expect(io.close(io.input())):eq(true) + + fs.delete(file) + end) + + it("support seeking", function() + setup() + io.input(file) + + expect(io.read(0)):eq("") -- not eof + expect(io.read(5, '*l')):eq('"�lo"') + expect(io.read(0)):eq("") + expect(io.read()):eq("second line") + local x = io.input():seek() + expect(io.read()):eq("third line ") + assert(io.input():seek("set", x)) + expect(io.read('*l')):eq("third line ") + expect(io.read(1)):eq("�") + expect(io.read(#"fourth_line")):eq("fourth_line") + assert(io.input():seek("cur", -#"fourth_line")) + expect(io.read()):eq("fourth_line") + expect(io.read()):eq("") -- empty line + expect(io.read(8)):eq('\9\9 3450') -- FIXME: Not actually supported + expect(io.read(1)):eq('\n') + expect(io.read(0)):eq(nil) -- end of file + expect(io.read(1)):eq(nil) -- end of file + expect(({ io.read(1) })[2]):eq(nil) + expect(io.read()):eq(nil) -- end of file + expect(({ io.read() })[2]):eq(nil) + expect(io.read('*n')):eq(nil) -- end of file + expect(({ io.read('*n') })[2]):eq(nil) + expect(io.read('*a')):eq('') -- end of file (OK for `*a') + expect(io.read('*a')):eq('') -- end of file (OK for `*a') + + io.close(io.input()) + end) + + it("supports the 'L' mode", function() + write_file(file, "\n\nline\nother") + + io.input(file) + expect(io.read"L"):eq("\n") + expect(io.read"L"):eq("\n") + expect(io.read"L"):eq("line\n") + expect(io.read"L"):eq("other") + expect(io.read"L"):eq(nil) + io.input():close() + + local f = assert(io.open(file)) + local s = "" + for l in f:lines("L") do s = s .. l end + expect(s):eq("\n\nline\nother") + f:close() + + io.input(file) + s = "" + for l in io.lines(nil, "L") do s = s .. l end + expect(s):eq("\n\nline\nother") + io.input():close() + + s = "" + for l in io.lines(file, "L") do s = s .. l end + expect(s):eq("\n\nline\nother") + + s = "" + for l in io.lines(file, "l") do s = s .. l end + expect(s):eq("lineother") + + write_file(file, "a = 10 + 34\na = 2*a\na = -a\n") + local t = {} + load(io.lines(file, "L"), nil, nil, t)() + expect(t.a):eq(-((10 + 34) * 2)) + end) + end) + + describe("a writable handle", function() + it("supports seeking", function() + fs.delete(file) + io.output(file) + + expect(io.output()):not_equals(io.stdout) + + expect(io.output():seek()):equal(0) + assert(io.write("alo alo")) + expect(io.output():seek()):equal(#"alo alo") + expect(io.output():seek("cur", -3)):equal(#"alo alo" - 3) + assert(io.write("joao")) + expect(io.output():seek("end")):equal(#"alo joao") + + expect(io.output():seek("set")):equal(0) + + assert(io.write('"�lo"', "{a}\n", "second line\n", "third line \n")) + assert(io.write('�fourth_line')) + + io.output(io.stdout) + expect(io.output()):equals(io.stdout) + end) + + it("supports appending", function() + io.output(file) + io.write("alo\n") + io.close() + expect.error(io.write) + + local f = io.open(file, "a") + io.output(f) + + assert(io.write(' ' .. t .. ' ')) + assert(io.write(';', 'end of file\n')) + f:flush() + io.flush() + f:close() + + expect(read_all(file)):eq("alo\n " .. t .. " ;end of file\n") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/keys_spec.lua b/src/test/resources/test-rom/spec/apis/keys_spec.lua new file mode 100644 index 000000000..8983543bc --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/keys_spec.lua @@ -0,0 +1,8 @@ +describe("The keys library", function() + describe("keys.getName", function() + it("validates arguments", function() + keys.getName(1) + expect.error(keys.getName, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/os_spec.lua b/src/test/resources/test-rom/spec/apis/os_spec.lua new file mode 100644 index 000000000..4797c8574 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/os_spec.lua @@ -0,0 +1,139 @@ +describe("The os library", function() + describe("os.date and os.time", function() + it("round trips correctly", function() + local t = math.floor(os.epoch("local") / 1000) + local T = os.date("*t", t) + + expect(os.time(T)):eq(t) + end) + + it("dst field is guessed", function() + local T = os.date("*t") + local t = os.time(T) + expect(T.isdst):type("boolean") + T.isdst = nil + expect(os.time(T)):eq(t) -- if isdst is absent uses correct default + end) + + it("has 365 days in a year", function() + local T = os.date("*t") + local t = os.time(T) + T.year = T.year - 1 + local t1 = os.time(T) + local delta = (t - t1) / (24 * 3600) - 365 + -- allow for leap years + assert(math.abs(delta) < 2, ("expected abs(%d )< 2"):format(delta)) + end) + + it("os.date uses local timezone", function() + local epoch = os.epoch("local") / 1000 + local date = os.time(os.date("*t")) + assert(date - epoch <= 2, ("expected %d - %d <= 2, but not the case"):format(date, epoch)) + end) + end) + + describe("os.date", function() + it("formats as expected", function() + -- From the PUC Lua tests, hence the weird style + local t = os.epoch("local") + local T = os.date("*t", t) + + _G.T = T + loadstring(os.date([[assert(T.year==%Y and T.month==%m and T.day==%d and + T.hour==%H and T.min==%M and T.sec==%S and + T.wday==%w+1 and T.yday==%j and type(T.isdst) == 'boolean')]], t))() + + T = os.date("!*t", t) + _G.T = T + loadstring(os.date([[!assert(T.year==%Y and T.month==%m and T.day==%d and + T.hour==%H and T.min==%M and T.sec==%S and + T.wday==%w+1 and T.yday==%j and type(T.isdst) == 'boolean')]], t))() + end) + + describe("produces output consistent with PUC Lua", function() + -- Create a separate test for each code, just so it's easier to see what's broken + local t1 = os.time { year = 2000, month = 10, day = 1, hour = 23, min = 12, sec = 17 } + local function exp_code(code, value) + it(("for code '%s'"):format(code), function() + expect(os.date(code, t1)):eq(value) + end) + end + + -- TODO: Java 16 apparently no longer treats TextStyle.FULL as full and will render Sun instead of Sunday. + exp_code("%a", "Sun") + -- exp_code("%A", "Sunday") + exp_code("%b", "Oct") + -- exp_code("%B", "October") + exp_code("%c", "Sun Oct 1 23:12:17 2000") + exp_code("%C", "20") + exp_code("%d", "01") + exp_code("%D", "10/01/00") + exp_code("%e", " 1") + exp_code("%F", "2000-10-01") + exp_code("%g", "00") + exp_code("%G", "2000") + exp_code("%h", "Oct") + exp_code("%H", "23") + exp_code("%I", "11") + exp_code("%j", "275") + exp_code("%m", "10") + exp_code("%M", "12") + exp_code("%n", "\n") + exp_code("%p", "PM") + exp_code("%r", "11:12:17 PM") + exp_code("%R", "23:12") + exp_code("%S", "17") + exp_code("%t", "\t") + exp_code("%T", "23:12:17") + exp_code("%u", "7") + exp_code("%U", "40") + exp_code("%V", "39") + exp_code("%w", "0") + exp_code("%W", "39") + exp_code("%x", "10/01/00") + exp_code("%X", "23:12:17") + exp_code("%y", "00") + exp_code("%Y", "2000") + exp_code("%%", "%") + + it("zones are numbers", function() + local zone = os.date("%z", t1) + if not zone:match("^[+-]%d%d%d%d$") then + error("Invalid zone: " .. zone) + end + end) + + it("zones id is made of letters", function() + local zone = os.date("%Z", t1) + if not zone:match("^%a%a+$") then + error("Non letter character in zone: " .. zone) + end + end) + + local t2 = os.time { year = 2000, month = 10, day = 1, hour = 3, min = 12, sec = 17 } + it("for code '%I' #2", function() + expect(os.date("%I", t2)):eq("03") + end) + end) + end) + + describe("os.time", function() + it("maps directly to seconds", function() + local t1 = os.time { year = 2000, month = 10, day = 1, hour = 23, min = 12, sec = 17 } + local t2 = os.time { year = 2000, month = 10, day = 1, hour = 23, min = 10, sec = 19 } + expect(t1 - t2):eq(60 * 2 - 2) + end) + end) + + describe("os.loadAPI", function() + it("validates arguments", function() + expect.error(os.loadAPI, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("os.unloadAPI", function() + it("validates arguments", function() + expect.error(os.loadAPI, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/paintutils_spec.lua b/src/test/resources/test-rom/spec/apis/paintutils_spec.lua new file mode 100644 index 000000000..f13bbcfd2 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/paintutils_spec.lua @@ -0,0 +1,176 @@ +local with_window = require "test_helpers".with_window + +describe("The paintutils library", function() + -- Verifies that a window's lines are equal to the given table of blit + -- strings ({{"text", "fg", "bg"}, {"text", "fg", "bg"}...}) + local function window_eq(w, state) + -- Verification of the size isn't really important in the tests, but + -- better safe than sorry. + local _, height = w.getSize() + expect(#state):eq(height) + + for line = 1, height do + expect({ w.getLine(line) }):same(state[line]) + end + end + + describe("paintutils.parseImage", function() + it("validates arguments", function() + paintutils.parseImage("") + expect.error(paintutils.parseImage, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("paintutils.loadImage", function() + it("validates arguments", function() + expect.error(paintutils.loadImage, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("paintutils.drawPixel", function() + it("validates arguments", function() + expect.error(paintutils.drawPixel, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(paintutils.drawPixel, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawPixel, 1, 1, false):eq("bad argument #3 (expected number, got boolean)") + end) + end) + + describe("paintutils.drawLine", function() + it("validates arguments", function() + expect.error(paintutils.drawLine, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(paintutils.drawLine, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawLine, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(paintutils.drawLine, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(paintutils.drawLine, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") + end) + + it("draws a line going across with custom colour", function() + local w = with_window(3, 2, function() + paintutils.drawLine(1, 1, 3, 1, colours.red) + end) + + window_eq(w, { + { " ", "000", "eee" }, + { " ", "000", "fff" }, + }) + end) + + it("draws a line going diagonally with term colour", function() + local w = with_window(3, 3, function() + term.setBackgroundColour(colours.red) + paintutils.drawLine(1, 1, 3, 3) + end) + + window_eq(w, { + { " ", "000", "eff" }, + { " ", "000", "fef" }, + { " ", "000", "ffe" }, + }) + end) + + it("draws a line going diagonally from bottom left", function() + local w = with_window(3, 3, function() + term.setBackgroundColour(colours.red) + paintutils.drawLine(1, 3, 3, 1) + end) + + window_eq(w, { + { " ", "000", "ffe" }, + { " ", "000", "fef" }, + { " ", "000", "eff" }, + }) + end) + end) + + describe("paintutils.drawBox", function() + it("validates arguments", function() + expect.error(paintutils.drawBox, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(paintutils.drawBox, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawBox, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(paintutils.drawBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(paintutils.drawBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") + end) + + it("draws a box with term colour", function() + local w = with_window(3, 3, function() + term.setBackgroundColour(colours.red) + paintutils.drawBox(1, 1, 3, 3) + end) + + window_eq(w, { + { " ", "eee", "eee" }, + { " ", "e0e", "efe" }, + { " ", "eee", "eee" }, + }) + end) + + it("draws a box with custom colour", function() + local w = with_window(3, 3, function() + paintutils.drawBox(1, 1, 3, 3, colours.red) + end) + + window_eq(w, { + { " ", "eee", "eee" }, + { " ", "e0e", "efe" }, + { " ", "eee", "eee" }, + }) + end) + + it("draws a box without overwriting existing content", function() + local w = with_window(3, 3, function() + term.setCursorPos(2, 2) + term.write("a") + paintutils.drawBox(1, 1, 3, 3, colours.red) + end) + + window_eq(w, { + { " ", "eee", "eee" }, + { " a ", "e0e", "efe" }, + { " ", "eee", "eee" }, + }) + end) + end) + + describe("paintutils.drawFilledBox", function() + it("validates arguments", function() + expect.error(paintutils.drawFilledBox, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(paintutils.drawFilledBox, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawFilledBox, 1, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(paintutils.drawFilledBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(paintutils.drawFilledBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") + end) + + it("draws a filled box with term colour", function() + local w = with_window(3, 3, function() + term.setBackgroundColour(colours.red) + paintutils.drawFilledBox(1, 1, 3, 3) + end) + + window_eq(w, { + { " ", "eee", "eee" }, + { " ", "eee", "eee" }, + { " ", "eee", "eee" }, + }) + end) + + it("draws a filled box with custom colour", function() + local w = with_window(3, 3, function() + paintutils.drawFilledBox(1, 1, 3, 3, colours.red) + end) + + window_eq(w, { + { " ", "eee", "eee" }, + { " ", "eee", "eee" }, + { " ", "eee", "eee" }, + }) + end) + end) + + describe("paintutils.drawImage", function() + it("validates arguments", function() + expect.error(paintutils.drawImage, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(paintutils.drawImage, {}, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(paintutils.drawImage, {}, 1, nil):eq("bad argument #3 (expected number, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/parallel_spec.lua b/src/test/resources/test-rom/spec/apis/parallel_spec.lua new file mode 100644 index 000000000..c8bd73648 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/parallel_spec.lua @@ -0,0 +1,124 @@ +describe("The parallel library", function() + describe("parallel.waitForAny", function() + it("validates arguments", function() + expect.error(parallel.waitForAny, ""):eq("bad argument #1 (expected function, got string)") + expect.error(parallel.waitForAny, function() end, 2):eq("bad argument #2 (expected function, got number)") + end) + + it("returns immediately with no arguments", function() + expect(parallel.waitForAny()):eq(0) + end) + + it("runs functions in parallel", function() + local entries = {} + local function a() + entries[#entries + 1] = "first" + local s = coroutine.yield() + entries[#entries + 1] = s + end + local function b() + entries[#entries + 1] = "second" + local s = coroutine.yield() + entries[#entries + 1] = s + end + os.queueEvent("yield") + parallel.waitForAny(a, b) + expect(entries):same({ "first", "second", "yield" }) + end) + + it("accepts an arbitrary number of functions", function() + local count = 0 + local fns = {} + for i = 1, 50 do fns[i] = function() + count = count + 1 + coroutine.yield() + end end + os.queueEvent("dummy") + parallel.waitForAny(table.unpack(fns)) + expect(count):eq(50) + end) + + it("passes errors to the caller", function() + expect.error(parallel.waitForAny, function() error("Test error") end):str_match("Test error$") + end) + + it("returns the number of the function that exited first", function() + os.queueEvent("dummy") + os.queueEvent("dummy") + expect(parallel.waitForAny(function() + coroutine.yield() + coroutine.yield() + end, function() + coroutine.yield() + return + end, function() + coroutine.yield() + coroutine.yield() + end)):eq(2) + end) + end) + + describe("parallel.waitForAll", function() + it("validates arguments", function() + expect.error(parallel.waitForAll, ""):eq("bad argument #1 (expected function, got string)") + expect.error(parallel.waitForAll, function() end, 2):eq("bad argument #2 (expected function, got number)") + end) + + it("returns immediately with no arguments", function() + parallel.waitForAll() + end) + + it("runs functions in parallel", function() + local entries = {} + local function a() + entries[#entries + 1] = "first" + local s = coroutine.yield() + entries[#entries + 1] = s + end + local function b() + entries[#entries + 1] = "second" + local s = coroutine.yield() + entries[#entries + 1] = s + end + os.queueEvent("yield") + parallel.waitForAll(a, b) + expect(entries):same({ "first", "second", "yield", "yield" }) + end) + + it("accepts an arbitrary number of functions", function() + local count = 0 + local fns = {} + for i = 1, 50 do fns[i] = function() + count = count + 1 + coroutine.yield() + end end + os.queueEvent("dummy") + parallel.waitForAll(table.unpack(fns)) + expect(count):eq(50) + end) + + it("passes errors to the caller", function() + expect.error(parallel.waitForAll, function() error("Test error") end):str_match("Test error$") + end) + + it("completes all functions before exiting", function() + local exitCount = 0 + os.queueEvent("dummy") + os.queueEvent("dummy") + parallel.waitForAll(function() + coroutine.yield() + coroutine.yield() + exitCount = exitCount + 1 + end, function() + coroutine.yield() + exitCount = exitCount + 1 + return + end, function() + coroutine.yield() + coroutine.yield() + exitCount = exitCount + 1 + end) + expect(exitCount):eq(3) + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua new file mode 100644 index 000000000..c64c042ce --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua @@ -0,0 +1,117 @@ +describe("The peripheral library", function() + local it_modem = peripheral.getType("top") == "modem" and it or pending + + local multitype_peripheral = setmetatable({}, { + __name = "peripheral", + name = "top", + type = "modem", + types = { "modem", "inventory", modem = true, inventory = true }, + }) + + describe("peripheral.isPresent", function() + it("validates arguments", function() + peripheral.isPresent("") + expect.error(peripheral.isPresent, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("peripheral.getName", function() + it("validates arguments", function() + expect.error(peripheral.getName, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(peripheral.getName, {}):eq("bad argument #1 (table is not a peripheral)") + end) + + it_modem("can get the name of a wrapped peripheral", function() + expect(peripheral.getName(peripheral.wrap("top"))):eq("top") + end) + end) + + describe("peripheral.getType", function() + it("validates arguments", function() + peripheral.getType("") + expect.error(peripheral.getType, nil):eq("bad argument #1 (expected string or table, got nil)") + expect.error(peripheral.getType, {}):eq("bad argument #1 (table is not a peripheral)") + end) + + it("returns nil when no peripheral is present", function() + expect(peripheral.getType("bottom")):eq(nil) + end) + + it_modem("can get the type of a peripheral by side", function() + expect(peripheral.getType("top")):eq("modem") + end) + + it_modem("can get the type of a wrapped peripheral", function() + expect(peripheral.getType(peripheral.wrap("top"))):eq("modem") + end) + + it("can return multiple types", function() + expect({ peripheral.getType(multitype_peripheral) }):same { "modem", "inventory" } + end) + end) + + describe("peripheral.hasType", function() + it("validates arguments", function() + peripheral.getType("") + expect.error(peripheral.hasType, nil):eq("bad argument #1 (expected string or table, got nil)") + expect.error(peripheral.hasType, {}, ""):eq("bad argument #1 (table is not a peripheral)") + expect.error(peripheral.hasType, ""):eq("bad argument #2 (expected string, got nil)") + end) + + it("returns nil when no peripherals are present", function() + expect(peripheral.hasType("bottom", "modem")):eq(nil) + end) + + it_modem("can check type of a peripheral by side", function() + expect(peripheral.hasType("top", "modem")):eq(true) + expect(peripheral.hasType("top", "not_a_modem")):eq(false) + end) + + it_modem("can check the type of a wrapped peripheral (true)", function() + expect(peripheral.hasType(peripheral.wrap("top"), "modem")):eq(true) + end) + + it("can check the type of a wrapped peripheral (fake)", function() + expect(peripheral.hasType(multitype_peripheral, "modem")):eq(true) + expect(peripheral.hasType(multitype_peripheral, "inventory")):eq(true) + expect(peripheral.hasType(multitype_peripheral, "something else")):eq(false) + end) + end) + + describe("peripheral.getMethods", function() + it("validates arguments", function() + peripheral.getMethods("") + expect.error(peripheral.getMethods, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("peripheral.call", function() + it("validates arguments", function() + peripheral.call("", "") + expect.error(peripheral.call, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(peripheral.call, "", nil):eq("bad argument #2 (expected string, got nil)") + end) + + it_modem("has the correct error location", function() + expect.error(function() peripheral.call("top", "isOpen", false) end) + :str_match("^[^:]+:%d+: bad argument #1 %(number expected, got boolean%)$") + end) + end) + + describe("peripheral.wrap", function() + it("validates arguments", function() + peripheral.wrap("") + expect.error(peripheral.wrap, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("peripheral.find", function() + it("validates arguments", function() + peripheral.find("") + peripheral.find("", function() + end) + expect.error(peripheral.find, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(peripheral.find, "", false):eq("bad argument #2 (expected function, got boolean)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/rednet_spec.lua b/src/test/resources/test-rom/spec/apis/rednet_spec.lua new file mode 100644 index 000000000..35cb4c1df --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/rednet_spec.lua @@ -0,0 +1,248 @@ +describe("The rednet library", function() + describe("rednet.open", function() + it("validates arguments", function() + expect.error(rednet.open, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("requires a modem to be present", function() + expect.error(rednet.open, "not_there"):eq("No such modem: not_there") + end) + end) + + describe("rednet.close", function() + it("validates arguments", function() + rednet.close() + expect.error(rednet.close, 1):eq("bad argument #1 (expected string, got number)") + expect.error(rednet.close, false):eq("bad argument #1 (expected string, got boolean)") + end) + + it("requires a modem to be present", function() + expect.error(rednet.close, "not_there"):eq("No such modem: not_there") + end) + end) + + describe("rednet.isOpen", function() + it("validates arguments", function() + rednet.isOpen() + rednet.isOpen("") + expect.error(rednet.isOpen, 1):eq("bad argument #1 (expected string, got number)") + expect.error(rednet.isOpen, false):eq("bad argument #1 (expected string, got boolean)") + end) + end) + + describe("rednet.send", function() + it("validates arguments", function() + rednet.send(1) + rednet.send(1, nil, "") + expect.error(rednet.send, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(rednet.send, 1, nil, false):eq("bad argument #3 (expected string, got boolean)") + end) + end) + + describe("rednet.broadcast", function() + it("validates arguments", function() + rednet.broadcast(nil) + rednet.broadcast(nil, "") + expect.error(rednet.broadcast, nil, false):eq("bad argument #2 (expected string, got boolean)") + end) + end) + + describe("rednet.receive", function() + it("validates arguments", function() + expect.error(rednet.receive, false):eq("bad argument #1 (expected string, got boolean)") + expect.error(rednet.receive, "", false):eq("bad argument #2 (expected number, got boolean)") + end) + end) + + describe("rednet.host", function() + it("validates arguments", function() + expect.error(rednet.host, "", "localhost"):eq("Reserved hostname") + expect.error(rednet.host, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(rednet.host, "", nil):eq("bad argument #2 (expected string, got nil)") + end) + end) + + describe("rednet.unhost", function() + it("validates arguments", function() + rednet.unhost("") + expect.error(rednet.unhost, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("rednet.lookup", function() + it("validates arguments", function() + expect.error(rednet.lookup, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(rednet.lookup, "", false):eq("bad argument #2 (expected string, got boolean)") + end) + + it("gets a locally hosted protocol", function() + rednet.host("a_protocol", "a_hostname") + + expect(rednet.lookup("a_protocol")):eq(os.getComputerID()) + expect(rednet.lookup("a_protocol", "localhost")):eq(os.getComputerID()) + expect(rednet.lookup("a_protocol", "a_hostname")):eq(os.getComputerID()) + end) + end) + + describe("on fake computers", function() + local fake_computer = require "support.fake_computer" + local debugx = require "support.debug_ext" + + local function dawdle() while true do coroutine.yield() end end + local function computer_with_rednet(id, fn, options) + local computer = fake_computer.make_computer(id, function(env) + local fns = { env.rednet.run } + if options and options.rep then + fns[#fns + 1] = function() env.dofile("rom/programs/rednet/repeat.lua") end + end + + if fn then + fns[#fns + 1] = function() + if options and options.open then + env.rednet.open("back") + env.os.queueEvent("x") env.os.pullEvent("x") + end + return fn(env.rednet, env) + end + end + + if options and options.host then + env.rednet.host("some_protocol", "host_" .. id) + end + + return parallel.waitForAny(table.unpack(fns)) + end) + local modem = fake_computer.add_modem(computer, "back") + fake_computer.add_api(computer, "rom/apis/rednet.lua") + return computer, modem + end + + it("opens and closes channels", function() + local id = math.random(256) + local computer = computer_with_rednet(id, function(rednet) + expect(rednet.isOpen()):eq(false) + + rednet.open("back") + rednet.open("front") + + expect(rednet.isOpen()):eq(true) + expect(rednet.isOpen("back")):eq(true) + expect(rednet.isOpen("front")):eq(true) + + rednet.close("back") + expect(rednet.isOpen("back")):eq(false) + expect(rednet.isOpen("front")):eq(true) + expect(rednet.isOpen()):eq(true) + + rednet.close() + + expect(rednet.isOpen("back")):eq(false) + expect(rednet.isOpen("front")):eq(false) + expect(rednet.isOpen()):eq(false) + end) + fake_computer.add_modem(computer, "front") + + fake_computer.run_all { computer } + end) + + it("sends and receives rednet messages", function() + local computer_1, modem_1 = computer_with_rednet(1, function(rednet) + rednet.send(2, "Hello") + end, { open = true }) + local computer_2, modem_2 = computer_with_rednet(2, function(rednet) + local id, message = rednet.receive() + expect(id):eq(1) + expect(message):eq("Hello") + end, { open = true }) + fake_computer.add_modem_edge(modem_1, modem_2) + + fake_computer.run_all { computer_1, computer_2 } + end) + + it("repeats messages between computers", function() + local computer_1, modem_1 = computer_with_rednet(1, function(rednet) + rednet.send(3, "Hello") + end, { open = true }) + local computer_2, modem_2 = computer_with_rednet(2, nil, { open = true, rep = true }) + local computer_3, modem_3 = computer_with_rednet(3, function(rednet) + local id, message = rednet.receive() + expect(id):eq(1) + expect(message):eq("Hello") + end, { open = true }) + fake_computer.add_modem_edge(modem_1, modem_2) + fake_computer.add_modem_edge(modem_2, modem_3) + + fake_computer.run_all({ computer_1, computer_2, computer_3 }, { computer_1, computer_3 }) + end) + + it("repeats messages between computers with massive ids", function() + local id_1, id_3 = 24283947, 93428798 + local computer_1, modem_1 = computer_with_rednet(id_1, function(rednet) + rednet.send(id_3, "Hello") + local id, message = rednet.receive() + expect { id, message }:same { id_3, "World" } + end, { open = true }) + local computer_2, modem_2 = computer_with_rednet(2, nil, { open = true, rep = true }) + local computer_3, modem_3 = computer_with_rednet(id_3, function(rednet) + rednet.send(id_1, "World") + local id, message = rednet.receive() + expect { id, message }:same { id_1, "Hello" } + end, { open = true }) + fake_computer.add_modem_edge(modem_1, modem_2) + fake_computer.add_modem_edge(modem_2, modem_3) + + fake_computer.run_all({ computer_1, computer_2, computer_3 }, { computer_1, computer_3 }) + end) + + it("ignores duplicate messages", function() + local computer_1, modem_1 = computer_with_rednet(1, function(rednet) + rednet.send(2, "Hello") + end, { open = true }) + local computer_2, modem_2 = computer_with_rednet(2, function(rednet, env) + local id, message = rednet.receive() + expect { id, message }:same { 1, "Hello" } + + local id = rednet.receive(nil, 1) + expect(id):eq(nil) + + env.sleep(10) + + -- Ensure our pending message store is empty. Bit ugly to prod internals, but there's no other way. + expect(debugx.getupvalue(rednet.run, "received_messages")):same({}) + expect(debugx.getupvalue(rednet.run, "prune_received_timer")):eq(nil) + end, { open = true }) + + local computer_3, modem_3 = computer_with_rednet(3, nil, { open = true, rep = true }) + fake_computer.add_modem_edge(modem_1, modem_3) + fake_computer.add_modem_edge(modem_3, modem_2) + + local computer_4, modem_4 = computer_with_rednet(4, nil, { open = true, rep = true }) + fake_computer.add_modem_edge(modem_1, modem_4) + fake_computer.add_modem_edge(modem_4, modem_2) + + local computers = { computer_1, computer_2, computer_3, computer_4 } + fake_computer.run_all(computers, false) + fake_computer.advance_all(computers, 1) + fake_computer.run_all(computers, { computer_1 }) + fake_computer.advance_all(computers, 10) + fake_computer.run_all(computers, { computer_1, computer_2 }) + end) + + it("handles lookups between computers with massive IDs", function() + local id_1, id_3 = 24283947, 93428798 + local computer_1, modem_1 = computer_with_rednet(id_1, function(rednet) + local ids = { rednet.lookup("some_protocol") } + expect(ids):same { id_3 } + end, { open = true }) + local computer_2, modem_2 = computer_with_rednet(2, nil, { open = true, rep = true }) + local computer_3, modem_3 = computer_with_rednet(id_3, dawdle, { open = true, host = true }) + fake_computer.add_modem_edge(modem_1, modem_2) + fake_computer.add_modem_edge(modem_2, modem_3) + + local computers = { computer_1, computer_2, computer_3 } + fake_computer.run_all(computers, false) + fake_computer.advance_all(computers, 3) + fake_computer.run_all(computers, { computer_1 }) + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/redstone_spec.lua b/src/test/resources/test-rom/spec/apis/redstone_spec.lua new file mode 100644 index 000000000..148d08700 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/redstone_spec.lua @@ -0,0 +1,92 @@ +local function it_side(func, ...) + local arg = table.pack(...) + it("requires a specific side", function() + expect.error(func, 0):eq("bad argument #1 (string expected, got number)") + expect.error(func, "blah", table.unpack(arg)):eq("bad argument #1 (unknown option blah)") + + func("top", table.unpack(arg)) + func("Top", table.unpack(arg)) + func("toP", table.unpack(arg)) + end) +end + +describe("The redstone library", function() + describe("redstone.setOutput", function() + it_side(redstone.setOutput, false) + + it("sets the output strength correctly", function() + redstone.setOutput("top", false) + expect(redstone.getAnalogueOutput("top")):eq(0) + + redstone.setOutput("top", true) + expect(redstone.getAnalogueOutput("top")):eq(15) + end) + end) + + describe("redstone.getOutput", function() + it_side(redstone.getOutput) + + it("gets the output strength correctly", function() + redstone.setAnalogueOutput("top", 0) + expect(redstone.getOutput("top")):eq(false) + + redstone.setAnalogueOutput("top", 1) + expect(redstone.getOutput("top")):eq(true) + + redstone.setAnalogueOutput("top", 15) + expect(redstone.getOutput("top")):eq(true) + end) + end) + + describe("redstone.getInput", function() + it_side(redstone.getInput) + end) + + describe("redstone.setAnalogueOutput", function() + it_side(redstone.setAnalogueOutput, 0) + + it("checks the strength parameter", function() + expect.error(redstone.setAnalogueOutput, "top", true):eq("bad argument #2 (number expected, got boolean)") + expect.error(redstone.setAnalogueOutput, "top", 0 / 0):eq("bad argument #2 (number expected, got nan)") + expect.error(redstone.setAnalogueOutput, "top", math.huge):eq("bad argument #2 (number expected, got inf)") + expect.error(redstone.setAnalogueOutput, "top", -1):eq("Expected number in range 0-15") + expect.error(redstone.setAnalogueOutput, "top", 16):eq("Expected number in range 0-15") + end) + end) + + describe("redstone.getAnalogueOutput", function() + it_side(redstone.getAnalogueOutput) + end) + + describe("redstone.getAnalogueInput", function() + it_side(redstone.getAnalogueInput) + end) + + describe("redstone.setBundledOutput", function() + it_side(redstone.setBundledOutput, 0) + + it("checks the mask parameter", function() + expect.error(redstone.setBundledOutput, "top", true):eq("bad argument #2 (number expected, got boolean)") + expect.error(redstone.setBundledOutput, "top", 0 / 0):eq("bad argument #2 (number expected, got nan)") + expect.error(redstone.setBundledOutput, "top", math.huge):eq("bad argument #2 (number expected, got inf)") + end) + end) + + describe("redstone.getBundledOutput", function() + it_side(redstone.getBundledOutput) + end) + + describe("redstone.getBundledInput", function() + it_side(redstone.getBundledInput) + end) + + describe("redstone.testBundledInput", function() + it_side(redstone.testBundledInput, 0) + + it("checks the mask parameter", function() + expect.error(redstone.testBundledInput, "top", true):eq("bad argument #2 (number expected, got boolean)") + expect.error(redstone.testBundledInput, "top", 0 / 0):eq("bad argument #2 (number expected, got nan)") + expect.error(redstone.testBundledInput, "top", math.huge):eq("bad argument #2 (number expected, got inf)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/settings_spec.lua b/src/test/resources/test-rom/spec/apis/settings_spec.lua new file mode 100644 index 000000000..1551a822a --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/settings_spec.lua @@ -0,0 +1,213 @@ +describe("The settings library", function() + describe("settings.define", function() + it("ensures valid type names", function() + expect.error(settings.define, "test.defined", { type = "function" }) + :eq('Unknown type "function". Expected one of number, string, boolean, table.') + end) + end) + describe("settings.undefine", function() + it("clears defined settings", function() + settings.define("test.unset", { default = 123 }) + settings.undefine("test.unset") + expect(settings.get("test.unset")):eq(nil) + end) + end) + + describe("settings.set", function() + it("validates arguments", function() + settings.set("test", 1) + settings.set("test", "") + settings.set("test", {}) + settings.set("test", false) + + expect.error(settings.set, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(settings.set, "", nil):eq("bad argument #2 (expected number, string, boolean or table, got nil)") + end) + + it("prevents storing unserialisable types", function() + expect.error(settings.set, "", { print }):eq("Cannot serialize type function") + end) + + it("setting changes the value", function() + local random = math.random(1, 0x7FFFFFFF) + settings.set("test", random) + expect(settings.get("test")):eq(random) + end) + + it("checks the type of the value", function() + settings.define("test.defined", { default = 123, description = "A description", type = "number" }) + expect.error(settings.set, "test.defined", "hello") + :eq("bad argument #2 (expected number, got string)") + settings.set("test.defined", 123) + end) + + it("setting fires an event", function() + settings.clear() + + local s = stub(os, "queueEvent") + settings.set("test", 1) + settings.set("test", 2) + + expect(s):called_with("setting_changed", "test", 1, nil) + expect(s):called_with("setting_changed", "test", 2, 1) + end) + end) + + describe("settings.get", function() + it("validates arguments", function() + settings.get("test") + expect.error(settings.get, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("returns the default", function() + expect(settings.get("test.undefined")):eq(nil) + expect(settings.get("test.undefined", "?")):eq("?") + + settings.define("test.unset", { default = "default" }) + expect(settings.get("test.unset")):eq("default") + expect(settings.get("test.unset", "?")):eq("?") + end) + end) + + describe("settings.getDetails", function() + it("validates arguments", function() + expect.error(settings.getDetails, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("works on undefined and unset values", function() + expect(settings.getDetails("test.undefined")):same { value = nil, changed = false } + end) + + it("works on undefined but set values", function() + settings.set("test", 456) + expect(settings.getDetails("test")):same { value = 456, changed = true } + end) + + it("works on defined but unset values", function() + settings.define("test.unset", { default = 123, description = "A description" }) + expect(settings.getDetails("test.unset")):same + { default = 123, value = 123, changed = false, description = "A description" } + end) + + it("works on defined and set values", function() + settings.define("test.defined", { default = 123, description = "A description", type = "number" }) + settings.set("test.defined", 456) + expect(settings.getDetails("test.defined")):same + { default = 123, value = 456, changed = true, description = "A description", type = "number" } + end) + end) + + describe("settings.unset", function() + it("validates arguments", function() + settings.unset("test") + expect.error(settings.unset, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("unsetting resets the value", function() + settings.set("test", true) + settings.unset("test") + expect(settings.get("test")):eq(nil) + end) + + it("unsetting does not touch defaults", function() + settings.define("test.defined", { default = 123 }) + settings.set("test.defined", 456) + settings.unset("test.defined") + expect(settings.get("test.defined")):eq(123) + end) + + it("unsetting fires an event", function() + settings.set("test", 1) + + local s = stub(os, "queueEvent") + settings.unset("test") + expect(s):called_with("setting_changed", "test", nil, 1) + end) + end) + + describe("settings.clear", function() + it("clearing resets all values", function() + settings.set("test", true) + settings.clear() + expect(settings.get("test")):eq(nil) + end) + + it("clearing does not touch defaults", function() + settings.define("test.defined", { default = 123 }) + settings.set("test.defined", 456) + settings.clear() + expect(settings.get("test.defined")):eq(123) + end) + + it("clearing fires an event", function() + settings.set("test", 1) + + local s = stub(os, "queueEvent") + settings.clear() + expect(s):called_with("setting_changed", "test", nil, 1) + end) + end) + + describe("settings.load", function() + it("validates arguments", function() + expect.error(settings.load, 1):eq("bad argument #1 (expected string, got number)") + end) + + local function setup_with(contents) + settings.clear() + local h = fs.open("/test-files/.settings", "w") + h.write(contents) + h.close() + + return settings.load("/test-files/.settings") + end + + local function setup(contents) + return setup_with(textutils.serialize(contents)) + end + + it("defaults to .settings", function() + local s = stub(fs, "open") + settings.load() + expect(s):called_with(".settings", "r") + end) + + it("loads undefined settings", function() + expect(setup { ["test"] = 1 }):eq(true) + expect(settings.get("test")):eq(1) + end) + + it("loads defined settings", function() + settings.define("test.defined", { type = "number" }) + expect(setup { ["test.defined"] = 1 }):eq(true) + expect(settings.get("test.defined")):eq(1) + end) + + it("skips defined settings with incorrect types", function() + settings.define("test.defined", { type = "number" }) + expect(setup { ["test.defined"] = "abc" }):eq(true) + expect(settings.get("test.defined")):eq(nil) + end) + + it("skips unserializable values", function() + expect(setup_with "{ test = function() end }"):eq(true) + expect(settings.get("test")):eq(nil) + end) + + it("skips non-table files", function() + expect(setup "not a table"):eq(false) + end) + end) + + describe("settings.save", function() + it("validates arguments", function() + expect.error(settings.save, 1):eq("bad argument #1 (expected string, got number)") + end) + + it("defaults to .settings", function() + local s = stub(fs, "open") + settings.save() + expect(s):called_with(".settings", "w") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/term_spec.lua b/src/test/resources/test-rom/spec/apis/term_spec.lua new file mode 100644 index 000000000..769fcb867 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/term_spec.lua @@ -0,0 +1,12 @@ +describe("The term library", function() + describe("term.redirect", function() + it("validates arguments", function() + expect.error(term.redirect, nil):eq("bad argument #1 (expected table, got nil)") + end) + + it("prevents redirecting to term", function() + expect.error(term.redirect, term) + :eq("term is not a recommended redirect target, try term.current() instead") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua new file mode 100644 index 000000000..71f426366 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -0,0 +1,252 @@ +local helpers = require "test_helpers" + +describe("The textutils library", function() + describe("textutils.slowWrite", function() + it("validates arguments", function() + expect.error(textutils.slowWrite, nil, false):eq("bad argument #2 (expected number, got boolean)") + end) + + it("wraps text correctly", function() + local count = 0 + stub(_G, "sleep", function() count = count + 1 end) + local w = helpers.with_window(20, 3, function() + textutils.slowWrite("This is a long string which one would hope wraps.") + end) + + expect(w.getLine(1)):eq "This is a long " + expect(w.getLine(2)):eq "string which one " + expect(w.getLine(3)):eq "would hope wraps. " + expect(count):eq(51) + end) + end) + + describe("textutils.formatTime", function() + it("validates arguments", function() + textutils.formatTime(0) + textutils.formatTime(0, false) + expect.error(textutils.formatTime, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(textutils.formatTime, 1, 1):eq("bad argument #2 (expected boolean, got number)") + end) + + it("correctly formats 12 o'clock", function() + expect(textutils.formatTime(0, false)):eq("12:00 AM") + expect(textutils.formatTime(0.1, false)):eq("12:06 AM") + + expect(textutils.formatTime(0, true)):eq("0:00") + expect(textutils.formatTime(0.1, true)):eq("0:06") + end) + end) + + describe("textutils.pagedPrint", function() + it("validates arguments", function() + expect.error(textutils.pagedPrint, nil, false):eq("bad argument #2 (expected number, got boolean)") + end) + end) + + describe("textutils.tabulate", function() + it("validates arguments", function() + term.redirect(window.create(term.current(), 1, 1, 5, 5, false)) + + textutils.tabulate() + textutils.tabulate({ "test", 1 }) + textutils.tabulate(colors.white) + + expect.error(textutils.tabulate, nil):eq("bad argument #1 (expected number or table, got nil)") + expect.error(textutils.tabulate, { "test" }, nil):eq("bad argument #2 (expected number or table, got nil)") + expect.error(textutils.tabulate, { false }):eq("bad argument #1.1 (expected string, got boolean)") + end) + end) + + describe("textutils.pagedTabulate", function() + it("validates arguments", function() + term.redirect(window.create(term.current(), 1, 1, 5, 5, false)) + + textutils.pagedTabulate() + textutils.pagedTabulate({ "test" }) + textutils.pagedTabulate(colors.white) + + expect.error(textutils.pagedTabulate, nil):eq("bad argument #1 (expected number or table, got nil)") + expect.error(textutils.pagedTabulate, { "test" }, nil):eq("bad argument #2 (expected number or table, got nil)") + end) + end) + + describe("textutils.empty_json_array", function() + it("is immutable", function() + expect.error(function() textutils.empty_json_array[1] = true end) + :str_match("^[^:]+:%d+: attempt to mutate textutils.empty_json_array$") + end) + end) + + describe("textutils.serialise", function() + it("serialises basic tables", function() + expect(textutils.serialise({ 1, 2, 3, a = 1, b = {} })) + :eq("{\n 1,\n 2,\n 3,\n a = 1,\n b = {},\n}") + + expect(textutils.serialise({ 0 / 0, 1 / 0, -1 / 0 })) + :eq("{\n 0/0,\n 1/0,\n -1/0,\n}") + end) + + it("fails on recursive/repeated tables", function() + local rep = {} + expect.error(textutils.serialise, { rep, rep }):eq("Cannot serialize table with repeated entries") + + local rep2 = { 1 } + expect.error(textutils.serialise, { rep2, rep2 }):eq("Cannot serialize table with repeated entries") + + local recurse = {} + recurse[1] = recurse + expect.error(textutils.serialise, recurse):eq("Cannot serialize table with recursive entries") + end) + + it("can allow repeated tables", function() + local rep = {} + expect(textutils.serialise({ rep, rep }, { allow_repetitions = true })):eq("{\n {},\n {},\n}") + + local rep2 = { 1 } + expect(textutils.serialise({ rep2, rep2 }, { allow_repetitions = true })):eq("{\n {\n 1,\n },\n {\n 1,\n },\n}") + + local recurse = {} + recurse[1] = recurse + expect.error(textutils.serialise, recurse, { allow_repetitions = true }):eq("Cannot serialize table with recursive entries") + end) + + it("can emit in a compact form", function() + expect(textutils.serialise({ 1, 2, 3, a = 1, [false] = {} }, { compact = true })) + :eq("{1,2,3,a=1,[false]={},}") + end) + end) + + describe("textutils.unserialise", function() + it("validates arguments", function() + textutils.unserialise("") + expect.error(textutils.unserialise, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("textutils.serialiseJSON", function() + it("validates arguments", function() + textutils.serialiseJSON("") + textutils.serialiseJSON(1) + textutils.serialiseJSON({}) + textutils.serialiseJSON(false) + textutils.serialiseJSON("", true) + expect.error(textutils.serialiseJSON, nil):eq("bad argument #1 (expected table, string, number or boolean, got nil)") + expect.error(textutils.serialiseJSON, "", 1):eq("bad argument #2 (expected boolean, got number)") + end) + + it("serializes empty arrays", function() + expect(textutils.serializeJSON(textutils.empty_json_array)):eq("[]") + end) + + it("serializes null", function() + expect(textutils.serializeJSON(textutils.json_null)):eq("null") + end) + + it("serializes strings", function() + expect(textutils.serializeJSON('a')):eq('"a"') + expect(textutils.serializeJSON('"')):eq('"\\""') + expect(textutils.serializeJSON('\\')):eq('"\\\\"') + expect(textutils.serializeJSON('/')):eq('"/"') + expect(textutils.serializeJSON('\b')):eq('"\\b"') + expect(textutils.serializeJSON('\n')):eq('"\\n"') + expect(textutils.serializeJSON(string.char(0))):eq('"\\u0000"') + expect(textutils.serializeJSON(string.char(0x0A))):eq('"\\n"') + expect(textutils.serializeJSON(string.char(0x1D))):eq('"\\u001D"') + expect(textutils.serializeJSON(string.char(0x81))):eq('"\\u0081"') + expect(textutils.serializeJSON(string.char(0xFF))):eq('"\\u00FF"') + end) + + it("serializes arrays until the last index with content", function() + expect(textutils.serializeJSON({ 5, "test", nil, nil, 7 })):eq('[5,"test",null,null,7]') + expect(textutils.serializeJSON({ 5, "test", nil, nil, textutils.json_null })):eq('[5,"test",null,null,null]') + expect(textutils.serializeJSON({ nil, nil, nil, nil, "text" })):eq('[null,null,null,null,"text"]') + end) + end) + + describe("textutils.unserializeJSON", function() + describe("parses", function() + it("a list of primitives", function() + expect(textutils.unserializeJSON('[1, true, false, "hello"]')):same { 1, true, false, "hello" } + end) + + it("null when parse_null is true", function() + expect(textutils.unserializeJSON("null", { parse_null = true })):eq(textutils.json_null) + end) + + it("null when parse_null is false", function() + expect(textutils.unserializeJSON("null", { parse_null = false })):eq(nil) + end) + + it("an empty array", function() + expect(textutils.unserializeJSON("[]", { parse_null = false })):eq(textutils.empty_json_array) + end) + + it("basic objects", function() + expect(textutils.unserializeJSON([[{ "a": 1, "b":2 }]])):same { a = 1, b = 2 } + end) + end) + + describe("parses using NBT-style syntax", function() + local function exp(x) + local res, err = textutils.unserializeJSON(x, { nbt_style = true }) + if not res then error(err, 2) end + return expect(res) + end + it("basic objects", function() + exp([[{ a: 1, b:2 }]]):same { a = 1, b = 2 } + end) + + it("suffixed numbers", function() + exp("1b"):eq(1) + exp("1.1d"):eq(1.1) + end) + + it("strings", function() + exp("'123'"):eq("123") + exp("\"123\""):eq("123") + end) + + it("typed arrays", function() + exp("[B; 1, 2, 3]"):same { 1, 2, 3 } + exp("[B;]"):same {} + end) + end) + + describe("passes nst/JSONTestSuite", function() + local search_path = "test-rom/data/json-parsing" + local skip = dofile(search_path .. "/skip.lua") + for _, file in pairs(fs.find(search_path .. "/*.json")) do + local name = fs.getName(file):sub(1, -6); + (skip[name] and pending or it)(name, function() + local h = io.open(file, "r") + local contents = h:read("*a") + h:close() + + local res, err = textutils.unserializeJSON(contents) + local kind = fs.getName(file):sub(1, 1) + if kind == "n" then + expect(res):eq(nil) + elseif kind == "y" then + if err ~= nil then fail("Expected test to pass, but failed with " .. err) end + end + end) + end + end) + end) + + describe("textutils.urlEncode", function() + it("validates arguments", function() + textutils.urlEncode("") + expect.error(textutils.urlEncode, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("textutils.complete", function() + it("validates arguments", function() + textutils.complete("pri") + textutils.complete("pri", _G) + expect.error(textutils.complete, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(textutils.complete, "", false):eq("bad argument #2 (expected table, got boolean)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/apis/window_spec.lua b/src/test/resources/test-rom/spec/apis/window_spec.lua new file mode 100644 index 000000000..6b5e7fdf7 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/window_spec.lua @@ -0,0 +1,173 @@ +describe("The window library", function() + local function mk() + return window.create(term.current(), 1, 1, 5, 5, false) + end + + describe("window.create", function() + it("validates arguments", function() + local r = mk() + window.create(r, 1, 1, 5, 5) + window.create(r, 1, 1, 5, 5, false) + + expect.error(window.create, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(window.create, r, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(window.create, r, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(window.create, r, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(window.create, r, 1, 1, 1, nil):eq("bad argument #5 (expected number, got nil)") + expect.error(window.create, r, 1, 1, 1, 1, ""):eq("bad argument #6 (expected boolean, got string)") + end) + end) + + describe("Window.blit", function() + it("validates arguments", function() + local w = mk() + w.blit("a", "a", "a") + + expect.error(w.blit, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(w.blit, "", nil):eq("bad argument #2 (expected string, got nil)") + expect.error(w.blit, "", "", nil):eq("bad argument #3 (expected string, got nil)") + expect.error(w.blit, "", "", "a"):eq("Arguments must be the same length") + end) + end) + + describe("Window.setCursorPos", function() + it("validates arguments", function() + local w = mk() + w.setCursorPos(1, 1) + + expect.error(w.setCursorPos, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.setCursorPos, 1, nil):eq("bad argument #2 (expected number, got nil)") + end) + end) + + describe("Window.setCursorBlink", function() + it("validates arguments", function() + local w = mk() + w.setCursorBlink(false) + expect.error(w.setCursorBlink, nil):eq("bad argument #1 (expected boolean, got nil)") + end) + end) + + describe("Window.setTextColour", function() + it("validates arguments", function() + local w = mk() + w.setTextColour(colors.white) + + expect.error(w.setTextColour, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.setTextColour, -5):eq("Invalid color (got -5)") + end) + end) + + describe("Window.setPaletteColour", function() + it("validates arguments", function() + local w = mk() + w.setPaletteColour(colors.white, 0, 0, 0) + w.setPaletteColour(colors.white, 0x000000) + + expect.error(w.setPaletteColour, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.setPaletteColour, -5):eq("Invalid color (got -5)") + expect.error(w.setPaletteColour, colors.white):eq("bad argument #2 (expected number, got nil)") + expect.error(w.setPaletteColour, colors.white, 1, false):eq("bad argument #3 (expected number, got boolean)") + expect.error(w.setPaletteColour, colors.white, 1, nil, 1):eq("bad argument #3 (expected number, got nil)") + expect.error(w.setPaletteColour, colors.white, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + end) + end) + + describe("Window.getPaletteColour", function() + it("validates arguments", function() + local w = mk() + w.getPaletteColour(colors.white) + expect.error(w.getPaletteColour, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.getPaletteColour, -5):eq("Invalid color (got -5)") + end) + end) + + describe("Window.setBackgroundColour", function() + it("validates arguments", function() + local w = mk() + w.setBackgroundColour(colors.white) + + expect.error(w.setBackgroundColour, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.setBackgroundColour, -5):eq("Invalid color (got -5)") + end) + end) + + describe("Window.scroll", function() + it("validates arguments", function() + local w = mk() + w.scroll(0) + expect.error(w.scroll, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) + + describe("Window.setVisible", function() + it("validates arguments", function() + local w = mk() + w.setVisible(false) + expect.error(w.setVisible, nil):eq("bad argument #1 (expected boolean, got nil)") + end) + end) + + describe("Window.reposition", function() + it("validates arguments", function() + local w = mk() + w.reposition(1, 1) + w.reposition(1, 1, 5, 5) + expect.error(w.reposition, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.reposition, 1, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(w.reposition, 1, 1, false, 1):eq("bad argument #3 (expected number, got boolean)") + expect.error(w.reposition, 1, 1, nil, 1):eq("bad argument #3 (expected number, got nil)") + expect.error(w.reposition, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(w.reposition, 1, 1, 1, 1, true):eq("bad argument #5 (expected table, got boolean)") + end) + + it("can change the buffer", function() + local a, b = mk(), mk() + local target = window.create(a, 1, 1, a.getSize()) + + target.write("Test") + expect((a.getLine(1))):equal("Test ") + expect({ a.getCursorPos() }):same { 5, 1 } + + target.reposition(1, 1, nil, nil, b) + + target.redraw() + expect((a.getLine(1))):equal("Test ") + expect({ a.getCursorPos() }):same { 5, 1 } + + target.setCursorPos(1, 1) target.write("More") + expect((a.getLine(1))):equal("Test ") + expect((b.getLine(1))):equal("More ") + end) + end) + + describe("Window.getLine", function() + it("validates arguments", function() + local w = mk() + w.getLine(1) + local _, y = w.getSize() + expect.error(w.getLine, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.getLine, 0):eq("Line is out of range.") + expect.error(w.getLine, y + 1):eq("Line is out of range.") + end) + + it("provides a line's contents", function() + local w = mk() + w.blit("test", "aaaa", "4444") + expect({ w.getLine(1) }):same { "test ", "aaaa0", "4444f" } + end) + end) + describe("Window.setVisible", function() + it("validates arguments", function() + local w = mk() + expect.error(w.setVisible, nil):eq("bad argument #1 (expected boolean, got nil)") + end) + end) + describe("Window.isVisible", function() + it("gets window visibility", function() + local w = mk() + w.setVisible(false) + expect(w.isVisible()):same(false) + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/base_spec.lua b/src/test/resources/test-rom/spec/base_spec.lua new file mode 100644 index 000000000..db7b69033 --- /dev/null +++ b/src/test/resources/test-rom/spec/base_spec.lua @@ -0,0 +1,110 @@ +local with_window = require "test_helpers".with_window + +describe("The Lua base library", function() + describe("sleep", function() + it("validates arguments", function() + sleep(0) + sleep(nil) + + expect.error(sleep, false):eq("bad argument #1 (expected number, got boolean)") + end) + end) + + describe("write", function() + it("validates arguments", function() + write("") + expect.error(write, nil):eq("bad argument #1 (expected string or number, got nil)") + end) + + it("writes numbers", function() + local w = with_window(5, 5, function() write(123) end) + expect(w.getLine(1)):eq("123 ") + end) + + it("writes strings", function() + local w = with_window(5, 5, function() write("abc") end) + expect(w.getLine(1)):eq("abc ") + end) + end) + + describe("loadfile", function() + local loadfile = _G.native_loadfile or loadfile + + local function make_file() + local tmp = fs.open("test-files/out.lua", "w") + tmp.write("return _ENV") + tmp.close() + end + + it("validates arguments", function() + loadfile("") + loadfile("", "") + loadfile("", "", {}) + + expect.error(loadfile, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(loadfile, "", false):eq("bad argument #2 (expected string, got boolean)") + expect.error(loadfile, "", "", false):eq("bad argument #3 (expected table, got boolean)") + end) + + it("prefixes the filename with @", function() + local info = debug.getinfo(loadfile("/rom/startup.lua"), "S") + expect(info):matches { short_src = "startup.lua", source = "@startup.lua" } + end) + + it("loads a file with the global environment", function() + make_file() + expect(loadfile("test-files/out.lua")()):eq(_G) + end) + + it("loads a file with a specific environment", function() + make_file() + local env = {} + expect(loadfile("test-files/out.lua", nil, env)()):eq(env) + end) + + it("supports the old-style argument form", function() + make_file() + local env = {} + expect(loadfile("test-files/out.lua", env)()):eq(env) + end) + end) + + describe("dofile", function() + it("validates arguments", function() + expect.error(dofile, ""):eq("File not found") + expect.error(dofile, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("load", function() + it("validates arguments", function() + load("") + load(function() + end) + load("", "") + load("", "", "") + load("", "", "", _ENV) + + expect.error(load, nil):eq("bad argument #1 (expected function or string, got nil)") + expect.error(load, "", false):eq("bad argument #2 (expected string, got boolean)") + expect.error(load, "", "", false):eq("bad argument #3 (expected string, got boolean)") + expect.error(load, "", "", "", false):eq("bad argument #4 (expected table, got boolean)") + end) + + local function generator(parts) + return coroutine.wrap(function() + for i = 1, #parts do + coroutine.yield(parts[i]) + end + end) + end + + it("does not prefix the chunk name with '='", function() + local info = debug.getinfo(load("return 1", "name"), "S") + expect(info):matches { short_src = "[string \"name\"]", source = "name" } + + info = debug.getinfo(load(generator { "return 1" }, "name"), "S") + expect(info):matches { short_src = "[string \"name\"]", source = "name" } + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/lua/README.md b/src/test/resources/test-rom/spec/lua/README.md new file mode 100644 index 000000000..9bd6c61a0 --- /dev/null +++ b/src/test/resources/test-rom/spec/lua/README.md @@ -0,0 +1,19 @@ +# Lua VM tests + +Unlike the rest of the test suites, the code in this folder doesn't test any +(well, much) CC code. Instead, it ensures that the Lua VM behaves in a way that +we expect. + +The VM that CC uses (LuaJ and later Cobalt) does not really conform to any one +version of Lua, instead supporting a myriad of features from Lua 5.1 to 5.3 (and +not always accurately). These tests attempt to pin down what behaviour is +required for a well behaved emulator. + + +These tests are split into several folders: + - `/` Tests for CC specific functionality, based on Cobalt/Lua quirks or needs + of CC. + - `puc`: Tests derived from the [PUC Lua test suite][puc-tests]. + + +[puc-tests]: https://www.lua.org/tests/ "Lua: test suites" diff --git a/src/test/resources/test-rom/spec/lua/coroutine_spec.lua b/src/test/resources/test-rom/spec/lua/coroutine_spec.lua new file mode 100644 index 000000000..2bf29e260 --- /dev/null +++ b/src/test/resources/test-rom/spec/lua/coroutine_spec.lua @@ -0,0 +1,330 @@ +describe("Coroutines", function() + local function assert_resume(ok, ...) + if ok then return table.pack(...) end + error(..., 0) + end + + --- Run a function in a coroutine, "echoing" the yielded value back as the resumption value. + local function coroutine_echo(f) + local co = coroutine.create(f) + local result = { n = 0 } + while coroutine.status(co) ~= "dead" do + result = assert_resume(coroutine.resume(co, table.unpack(result, 1, result.n))) + end + + return table.unpack(result, 1, result.n) + end + + describe("allow yielding", function() + --[[ + Tests for some non-standard yield locations. I'm not saying that users + /should/ use this, but it's useful for us to allow it in order to suspend the + VM in arbitrary locations. + + Cobalt does support this within load too, but that's unlikely to be supported + in the future. + + These tests were split over about 7 files in Cobalt and are in one massive one + in this test suite. Sorry. + ]] + + it("within debug hooks", function() + coroutine_echo(function() + local counts = { call = 0, ['return'] = 0, count = 0, line = 0 } + + debug.sethook(function(kind) + counts[kind] = (counts[kind] or 0) + 1 + expect(coroutine.yield(kind)):eq(kind) + end, "crl", 1) + + expect(string.gsub("xyz", "x", "z")):eq("zyz") + expect(pcall(function() + local x = 0 + for i = 1, 5 do x = x + i end + end)):eq(true) + + debug.sethook(nil) + + -- These numbers are going to vary beyond the different VMs a + -- little. As long as they're non-0, it's all fine. + expect(counts.call):ne(0) + expect(counts['return']):ne(0) + expect(counts.count):ne(0) + expect(counts.line):ne(0) + end) + end) + + it("within string.gsub", function() + local result, count = coroutine_echo(function() + return ("hello world"):gsub("%w", function(entry) + local x = coroutine.yield(entry) + return x:upper() + end) + end) + + expect(result):eq("HELLO WORLD") + expect(count):eq(10) + end) + + describe("within pcall", function() + it("with no error", function() + local ok, a, b, c = coroutine_echo(function() + return pcall(function() + local a, b, c = coroutine.yield(1, 2, 3) + return a, b, c + end) + end) + + expect(ok):eq(true) + expect({ a, b, c }):same { 1, 2, 3 } + end) + + it("with an error", function() + local ok, msg = coroutine_echo(function() + return pcall(function() + local a, b, c = coroutine.yield(1, 2, 3) + expect({ a, b, c }):same { 1, 2, 3 } + error("Error message", 0) + end) + end) + + expect(ok):eq(false) + expect(msg):eq("Error message") + end) + end) + + it("within table.foreach", function() + coroutine_echo(function() + local x = { 3, "foo", 4, 1 } + local idx = 1 + table.foreach(x, function(key, val) + expect(key):eq(idx) + expect(val):eq(x[idx]) + expect(coroutine.yield(val)):eq(val) + + idx = idx + 1 + end) + end) + end) + + it("within table.foreachi", function() + coroutine_echo(function() + local x = { 3, "foo", 4, 1 } + local idx = 1 + table.foreachi(x, function(key, val) + expect(key):eq(idx) + expect(val):eq(x[idx]) + expect(coroutine.yield(val)):eq(val) + + idx = idx + 1 + end) + end) + end) + + describe("within table.sort", function() + it("with a yielding comparator", function() + coroutine_echo(function() + local x = { 32, 2, 4, 13 } + table.sort(x, function(a, b) + local x, y = coroutine.yield(a, b) + expect(x):eq(a) + expect(y):eq(b) + + return a < b + end) + + expect(x[1]):eq(2) + expect(x[2]):eq(4) + expect(x[3]):eq(13) + expect(x[4]):eq(32) + end) + end) + + it("within a yielding metatable comparator", function() + local meta = { + __lt = function(a, b) + local x, y = coroutine.yield(a, b) + expect(x):eq(a) + expect(y):eq(b) + + return a.x < b.x + end, + } + + local function create(val) return setmetatable({ x = val }, meta) end + + coroutine_echo(function() + local x = { create(32), create(2), create(4), create(13) } + table.sort(x) + + expect(x[1].x):eq(2) + expect(x[2].x):eq(4) + expect(x[3].x):eq(13) + expect(x[4].x):eq(32) + end) + end) + end) + + describe("within xpcall", function() + it("within the main function", function() + -- Ensure that yielding within a xpcall works as expected + coroutine_echo(function() + local ok, a, b, c = xpcall(function() + return coroutine.yield(1, 2, 3) + end, function(msg) return msg .. "!" end) + + expect(true):eq(ok) + expect(1):eq(a) + expect(2):eq(b) + expect(3):eq(c) + end) + end) + + it("within the main function (with an error)", function() + coroutine_echo(function() + local ok, msg = xpcall(function() + local a, b, c = coroutine.yield(1, 2, 3) + expect(1):eq(a) + expect(2):eq(b) + expect(3):eq(c) + + error("Error message", 0) + end, function(msg) return msg .. "!" end) + + expect(false):eq(ok) + expect("Error message!"):eq(msg) + end) + end) + + it("with an error in the error handler", function() + coroutine_echo(function() + local ok, msg = xpcall(function() + local a, b, c = coroutine.yield(1, 2, 3) + expect(1):eq(a) + expect(2):eq(b) + expect(3):eq(c) + + error("Error message") + end, function(msg) error(msg) end) + + expect(false):eq(ok) + expect("error in error handling"):eq(msg) + end) + end) + + it("within the error handler", function() + coroutine_echo(function() + local ok, msg = xpcall(function() + local a, b, c = coroutine.yield(1, 2, 3) + expect(1):eq(a) + expect(2):eq(b) + expect(3):eq(c) + + error("Error message", 0) + end, function(msg) + return coroutine.yield(msg) .. "!" + end) + + expect(false):eq(ok) + expect("Error message!"):eq(msg) + end) + end) + + it("within the error handler with an error", function() + coroutine_echo(function() + local ok, msg = xpcall(function() + local a, b, c = coroutine.yield(1, 2, 3) + expect(1):eq(a) + expect(2):eq(b) + expect(3):eq(c) + + error("Error message", 0) + end, function(msg) + coroutine.yield(msg) + error("nope") + end) + + expect(false):eq(ok) + expect("error in error handling"):eq(msg) + end) + end) + end) + + it("within metamethods", function() + local create, ops + create = function(val) return setmetatable({ x = val }, ops) end + ops = { + __add = function(x, y) + local a, b = coroutine.yield(x, y) + return create(a.x + b.x) + end, + __div = function(x, y) + local a, b = coroutine.yield(x, y) + return create(a.x / b.x) + end, + __concat = function(x, y) + local a, b = coroutine.yield(x, y) + return create(a.x .. b.x) + end, + __eq = function(x, y) + local a, b = coroutine.yield(x, y) + return a.x == b.x + end, + __lt = function(x, y) + local a, b = coroutine.yield(x, y) + return a.x < b.x + end, + __index = function(tbl, key) + local res = coroutine.yield(key) + return res:upper() + end, + __newindex = function(tbl, key, val) + local rKey, rVal = coroutine.yield(key, val) + rawset(tbl, rKey, rVal .. "!") + end, + } + + local varA = create(2) + local varB = create(3) + + coroutine_echo(function() + expect(5):eq((varA + varB).x) + expect(5):eq((varB + varA).x) + expect(4):eq((varA + varA).x) + expect(6):eq((varB + varB).x) + + expect(2 / 3):eq((varA / varB).x) + expect(3 / 2):eq((varB / varA).x) + expect(1):eq((varA / varA).x) + expect(1):eq((varB / varB).x) + + expect("23"):eq((varA .. varB).x) + expect("32"):eq((varB .. varA).x) + expect("22"):eq((varA .. varA).x) + expect("33"):eq((varB .. varB).x) + expect("33333"):eq((varB .. varB .. varB .. varB .. varB).x) + + expect(false):eq(varA == varB) + expect(false):eq(varB == varA) + expect(true):eq(varA == varA) + expect(true):eq(varB == varB) + + expect(true):eq(varA < varB) + expect(false):eq(varB < varA) + expect(false):eq(varA < varA) + expect(false):eq(varB < varB) + + expect(true):eq(varA <= varB) + expect(false):eq(varB <= varA) + expect(true):eq(varA <= varA) + expect(true):eq(varB <= varB) + + expect("HELLO"):eq(varA.hello) + varA.hello = "bar" + expect("bar!"):eq(varA.hello) + end) + + + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/lua/timeout_spec.lua b/src/test/resources/test-rom/spec/lua/timeout_spec.lua new file mode 100644 index 000000000..159130d4c --- /dev/null +++ b/src/test/resources/test-rom/spec/lua/timeout_spec.lua @@ -0,0 +1,17 @@ +describe("The VM terminates long running code :slow", function() + it("in loops", function() + expect.error(function() while true do end end) + :str_match("^.+:%d+: Too long without yielding$") + end) + + describe("in string pattern matching", function() + local str, pat = ("a"):rep(1e4), ".-.-.-.-b$" + + it("string.find", function() + expect.error(string.find, str, pat):eq("Too long without yielding") + end) + it("string.match", function() + expect.error(string.match, str, pat):eq("Too long without yielding") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/lua/vm_spec.lua b/src/test/resources/test-rom/spec/lua/vm_spec.lua new file mode 100644 index 000000000..702306939 --- /dev/null +++ b/src/test/resources/test-rom/spec/lua/vm_spec.lua @@ -0,0 +1,9 @@ +describe("The VM", function() + it("allows unpacking a large number of values", function() + -- We don't allow arbitrarily many values, half a meg is probably fine. + -- I don't actually have any numbers on this - maybe we do need more? + local len = 2 ^ 19 + local tbl = { (" "):rep(len):byte(1, -1) } + expect(#tbl):eq(len) + end) +end) diff --git a/src/test/resources/test-rom/spec/modules/cc/audio/dfpwm_spec.lua b/src/test/resources/test-rom/spec/modules/cc/audio/dfpwm_spec.lua new file mode 100644 index 000000000..dbc28ca01 --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/audio/dfpwm_spec.lua @@ -0,0 +1,26 @@ +describe("cc.audio.dfpwm", function() + local dfpwm = require "cc.audio.dfpwm" + + describe("decode", function() + it("decodes some test data", function() + -- Look, I'm not proud of this. + local input = "\43\225\33\44\30\240\171\23\253\201\46\186\68\189\74\160\188\16\94\169\251\87\11\240\19\92\85\185\126\5\172\64\17\250\85\245\255\169\244\1\85\200\33\176\82\104\163\17\126\23\91\226\37\224\117\184\198\11\180\19\148\86\191\246\255\188\231\10\210\85\124\202\15\232\43\162\117\63\220\15\250\88\87\230\173\106\41\13\228\143\246\190\119\169\143\68\201\40\149\62\20\72\3\160\114\169\254\39\152\30\20\42\84\24\47\64\43\61\221\95\191\42\61\42\206\4\247\81" + local output = { 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, -1, -2, -2, -1, 0, 1, 0, -1, -3, -5, -5, -5, -7, -9, -11, -11, -9, -9, -9, -9, -10, -12, -12, -10, -8, -6, -6, -8, -10, -12, -14, -16, -18, -17, -15, -12, -9, -6, -3, -2, -2, -2, -2, -2, -2, 0, 3, 6, 7, 7, 7, 4, 1, 1, 1, 1, 3, 5, 7, 9, 12, 15, 15, 12, 12, 12, 9, 9, 11, 12, 12, 14, 16, 17, 17, 17, 14, 11, 11, 11, 10, 12, 14, 14, 13, 13, 10, 9, 9, 7, 5, 4, 4, 4, 4, 4, 6, 8, 10, 10, 10, 10, 10, 10, 10, 9, 8, 8, 8, 7, 6, 4, 2, 0, 0, 0, 0, 0, -1, -1, 0, 1, 3, 3, 3, 3, 2, 0, -2, -2, -2, -3, -5, -7, -7, -5, -3, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -1, -1, 0, 1, 1, 1, 2, 3, 4, 5, 6, 7, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 9, 8, 7, 6, 4, 2, 0, 0, 2, 4, 6, 8, 10, 10, 8, 7, 7, 5, 3, 1, -1, 0, 2, 4, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 4, 5, 5, 5, 5, 5, 6, 7, 8, 9, 10, 9, 9, 9, 9, 9, 8, 7, 6, 5, 3, 1, 1, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -3, -3, -3, -3, -2, -3, -4, -4, -3, -4, -5, -6, -6, -5, -5, -4, -3, -2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 20, 17, 16, 16, 15, 15, 15, 15, 13, 13, 13, 13, 14, 15, 16, 18, 18, 16, 14, 12, 10, 8, 5, 5, 5, 4, 4, 4, 4, 4, 4, 2, 0, -2, -2, -2, -4, -4, -2, 0, 0, -2, -4, -6, -6, -6, -8, -10, -12, -14, -16, -15, -13, -12, -11, -11, -11, -11, -13, -13, -13, -13, -13, -14, -16, -18, -18, -18, -18, -16, -16, -16, -14, -13, -14, -15, -15, -14, -14, -12, -11, -12, -13, -13, -12, -13, -14, -15, -15, -13, -11, -9, -7, -5, -5, -5, -3, -1, -1, -1, -1, -3, -5, -5, -3, -3, -3, -1, -1, -1, -1, -3, -3, -3, -4, -6, -6, -4, -2, 0, 0, 0, 0, -2, -2, -2, -3, -5, -7, -9, -11, -13, -13, -11, -9, -7, -6, -6, -6, -6, -4, -2, -2, -4, -6, -8, -7, -5, -3, -2, -2, -2, -2, 0, 0, -2, -4, -4, -2, 0, 2, 2, 1, 1, -1, -3, -5, -7, -10, -10, -10, -10, -8, -7, -7, -5, -3, -2, -4, -4, -4, -6, -8, -10, -12, -12, -12, -12, -12, -14, -13, -13, -13, -11, -11, -11, -11, -11, -11, -11, -9, -7, -5, -3, -1, -1, -1, -1, -1, 1, 1, 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 22, 19, 18, 20, 22, 24, 23, 22, 24, 26, 28, 27, 24, 23, 25, 28, 28, 28, 27, 26, 26, 23, 20, 17, 14, 14, 14, 11, 11, 11, 11, 13, 15, 16, 16, 16, 15, 15, 14, 14, 12, 10, 9, 11, 13, 15, 17, 17, 14, 13, 13, 12, 12, 10, 9, 11, 13, 15, 17, 19, 19, 16, 13, 10, 7, 4, 1, 1, 2, 2, 4, 7, 10, 13, 13, 13, 12, 12, 12, 9, 6, 6, 6, 3, 0, 0, 0, 0, 2, 3, 3, 3, 3, 5, 7, 7, 7, 9, 11, 13, 15, 18, 18, 15, 12, 9, 8, 10, 13, 13, 13, 15, 18, 21, 24, 27, 27, 23, 19, 15, 11, 10, 9, 9, 12, 16, 19, 22, 23, 19, 14, 13, 16, 16, 15, 15, 14, 17, 20, 20, 19, 19, 18, 17, 14, 13, 15, 15, 12, 11, 13, 16, 19, 19, 18, 20, 20, 19, 18, 18, 17, 17, 16, 16, 16, 15, 17, 17, 16, 16, 13, 12, 12, 11, 11, 9, 9, 9, 9, 11, 11, 9, 7, 5, 3, 1, 1, 1, -1, -1, 1, 3, 5, 7, 9, 11, 12, 9, 6, 6, 6, 6, 8, 8, 7, 9, 11, 13, 13, 12, 14, 16, 18, 20, 20, 20, 22, 24, 26, 25, 25, 27, 29, 28, 27, 26, 23, 22, 22, 21, 21, 20, 22, 24, 26, 28, 27, 24, 21, 21, 21, 18, 17, 17, 14, 11, 11, 11, 10, 10, 7, 6, 6, 4, 3, 5, 5, 3, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 0, 0, 1, 2, 3, 4, 3, 1, -1, -3, -3, -3, -3, -2, -3, -4, -6, -8, -10, -10, -10, -12, -12, -12, -12, -10, -10, -11, -12, -14, -16, -18, -20, -22, -24, -26, -28, -27, -27, -26, -26, -25, -25, -27, -26, -24, -22, -22, -22, -22, -24, -24, -24, -24, -23, -23, -22, -22, -21, -20, -19, -17, -15, -13, -11, -9, -7, -7, -9, -9, -9, -11, -13, -15, -17, -16, -14, -13, -15, -14, -14, -14, -12, -10, -8, -7, -9, -11, -13, -15, -14, -14, -13, -13, -15, -17, -19, -18, -18, -17, -17, -16, -16, -18, -20, -22, -21, -21, -21, -21, -21, -20, -21, -22, -24, -24, -22, -22, -24, -26, -25, -23, -21, -19, -18, -17, -17, -19, -21, -23, -25, -27, -29, -31, -30, -29, -28, -26, -25, -24, -24, -23, -23, -25, -24, -24, -24, -22, -20, -18, -18, -20, -20, -20, -20, -18, -16, -16, -16, -14, -12, -10, -8, -6, -4, -4, -4, -4, -4, -2, 0, 2, 4, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 4, 5, 6, 5, 3, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, -1, -2, -3, -4, -4, -2, 0, 0, 0, 1, 3, 5, 7, 7, 5, 3, 3, 3, 3, 3 } + + local decoded = dfpwm.decode(input) + expect(#decoded):describe("The lengths match"):eq(#output) + for i = 1, #decoded do expect(decoded[i]):describe("Item at #" .. i):eq(output[i]) end + end) + end) + + describe("encode", function() + it("encodes some data", function() + local input = { 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -6, -6, -6, -7, -7, -7, -7, -7, -7, -7, -7, -7, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -5, -5, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -7, -7, -7, -7, -7, -7, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3 } + local output = { 87, 74, 42, 165, 164, 148, 84, 169, 170, 86, 173, 90, 173, 213, 90, 171, 214, 106, 213, 170, 106, 149, 42, 149, 74, 169, 74, 165, 74, 165, 170, 170, 106, 85, 107, 173, 106, 173, 173, 86, 181, 170, 42, 85, 149, 82, 41, 165, 82, 74, 41, 149, 170, 212, 170, 86, 181, 106, 173, 181, 170, 181, 90, 173, 170, 170, 170, 82, 165, 74, 149, 170, 82, 169, 82, 85, 85, 85, 173, 86, 181, 170, 213, 90, 173, 90, 85, 85, 149, 42, 165, 82, 170, 82, 74, 41, 85, 169, 170, 170, 106, 181, 90, 173, 86, 171, 106, 213, 106, 85, 85, 85, 85, 149, 42, 85, 170, 42, 149, 170, 170, 170, 170, 106, 181, 170, 86, 171 } + + local encoded = dfpwm.encode(input) + expect(#encoded):describe("The lengths match"):eq(#output) + for i = 1, #encoded do expect(encoded:byte(i)):describe("Item at #" .. i):eq(output[i] % 256) end + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/modules/cc/completion_spec.lua b/src/test/resources/test-rom/spec/modules/cc/completion_spec.lua new file mode 100644 index 000000000..41e7ae5bc --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/completion_spec.lua @@ -0,0 +1,57 @@ +describe("cc.completion", function() + local c = require("cc.completion") + + describe("choice", function() + it("provides all choices", function() + expect(c.choice("", { "some text", "some other", "other" })) + :same { "some text", "some other", "other" } + end) + + it("provides a filtered list of choices", function() + expect(c.choice("som", { "some text", "some other", "other" })) + :same { "e text", "e other" } + + expect(c.choice("none", { "some text", "some other", "other" })) + :same { } + end) + + it("adds text if needed", function() + expect(c.choice("som", { "some text", "some other", "other" }, true)) + :same { "e text ", "e other " } + end) + end) + + describe("peripheral", function() + it("provides a choice of peripherals", function() + stub(peripheral, "getNames", function() return { "drive_0", "left" } end) + + expect(c.peripheral("dri")):same { "ve_0" } + expect(c.peripheral("dri", true)):same { "ve_0 " } + end) + end) + + describe("side", function() + it("provides a choice of sides", function() + expect(c.side("le")):same { "ft" } + expect(c.side("le", true)):same { "ft " } + end) + end) + + describe("setting", function() + it("provides a choice of setting names", function() + stub(settings, "getNames", function() return { "shell.allow_startup", "list.show_hidden" } end) + + expect(c.setting("li")):same { "st.show_hidden" } + expect(c.setting("li", true)):same { "st.show_hidden " } + end) + end) + + describe("command", function() + it("provides a choice of command names", function() + stub(_G, "commands", { list = function() return { "list", "say" } end }) + + expect(c.command("li")):same { "st" } + expect(c.command("li", true)):same { "st " } + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua b/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua new file mode 100644 index 000000000..98c91e53e --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua @@ -0,0 +1,74 @@ +describe("cc.expect", function() + local e = require("cc.expect") + + describe("expect", function() + it("checks a single type", function() + expect(e.expect(1, "test", "string")):eq("test") + expect(e.expect(1, 2, "number")):eq(2) + + expect.error(e.expect, 1, nil, "string"):eq("bad argument #1 (expected string, got nil)") + expect.error(e.expect, 2, 1, "nil"):eq("bad argument #2 (expected nil, got number)") + end) + + it("checks multiple types", function() + expect(e.expect(1, "test", "string", "number")):eq("test") + expect(e.expect(1, 2, "string", "number")):eq(2) + + expect.error(e.expect, 1, nil, "string", "number"):eq("bad argument #1 (expected string or number, got nil)") + expect.error(e.expect, 2, false, "string", "table", "number", "nil") + :eq("bad argument #2 (expected string, table or number, got boolean)") + end) + + it("includes the function name", function() + local function worker() + expect(e.expect(1, nil, "string")):eq(true) + end + local function trampoline() + worker() + end + + expect.error(trampoline):str_match("^[^:]*expect_spec.lua:27: bad argument #1 to 'worker' %(expected string, got nil%)$") + end) + end) + + describe("field", function() + it("checks a single type", function() + expect(e.field({ k = "test" }, "k", "string")):eq("test") + expect(e.field({ k = 2 }, "k", "number")):eq(2) + + expect.error(e.field, { k = nil }, "k", "string"):eq("field 'k' missing from table") + expect.error(e.field, { l = 1 }, "l", "nil"):eq("bad field 'l' (expected nil, got number)") + end) + + it("checks multiple types", function() + expect(e.field({ k = "test" }, "k", "string", "number")):eq("test") + expect(e.field({ k = 2 }, "k", "string", "number")):eq(2) + + expect.error(e.field, { k = nil }, "k", "string", "number") + :eq("field 'k' missing from table") + expect.error(e.field, { l = false }, "l", "string", "table", "number", "nil") + :eq("bad field 'l' (expected string, table or number, got boolean)") + end) + end) + + describe("range", function() + it("works fith full args", function() + expect(e.range(1, 1, 1)):eq(1) + expect(e.range(2, 1, 3)):eq(2) + + expect.error(e.range, 2, 0, 1):eq("number outside of range (expected 2 to be within 0 and 1)") + expect.error(e.range, 0, 1, 2):eq("number outside of range (expected 0 to be within 1 and 2)") + local NaN = 0 / 0 + expect.error(e.range, NaN, 1, 2):eq(("number outside of range (expected %s to be within 1 and 2)"):format(tostring(NaN))) + end) + + it("fills in min and max if they are nil", function() + expect(e.range(1, 1)):eq(1) + expect(e.range(2, nil, 3)):eq(2) + expect(e.range(2)):eq(2) + + expect.error(e.range, 2, nil, 1):eq("number outside of range (expected 2 to be within -inf and 1)") + expect.error(e.range, 0, 1):eq("number outside of range (expected 0 to be within 1 and inf)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/modules/cc/image/nft_spec.lua b/src/test/resources/test-rom/spec/modules/cc/image/nft_spec.lua new file mode 100644 index 000000000..f67c40898 --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/image/nft_spec.lua @@ -0,0 +1,91 @@ +local helpers = require "test_helpers" + +describe("cc.image.nft", function() + local nft = require("cc.image.nft") + + describe("parse", function() + it("validates arguments", function() + nft.parse("") + expect.error(nft.parse, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("parses an empty string", function() + expect(nft.parse("")):same {} + end) + + it("parses a string with no colours", function() + expect(nft.parse("Hello")):same { { text = "Hello", foreground = "00000", background = "fffff" } } + end) + + it("handles background and foreground colours", function() + expect(nft.parse("\30a\31bHello")) + :same { { text = "Hello", foreground = "bbbbb", background = "aaaaa" } } + end) + + it("parses multi-line files", function() + expect(nft.parse("Hello\nWorld")):same { + { text = "Hello", foreground = "00000", background = "fffff" }, + { text = "World", foreground = "00000", background = "fffff" }, + } + end) + + it("handles empty lines", function() + expect(nft.parse("\n\n")):same { + { text = "", foreground = "", background = "" }, + { text = "", foreground = "", background = "" }, + } + end) + end) + + describe("load", function() + it("validates arguments", function() + nft.load("") + expect.error(nft.load, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("loads from a file", function() + local image = fs.open("/test-files/example.nft", "w") + image.write("\30aHello, world!") + image.close() + + expect(nft.load("/test-files/example.nft")):same { + { background = "aaaaaaaaaaaaa", foreground = "0000000000000", text = "Hello, world!" }, + } + end) + + it("fails on missing files", function() + expect({ nft.load("/test-files/not_a_file.nft") }) + :same { nil, "/test-files/not_a_file.nft: No such file" } + end) + end) + + describe("draw", function() + it("validates arguments", function() + expect.error(nft.draw, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(nft.draw, {}, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(nft.draw, {}, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(nft.draw, {}, 1, 1, false):eq("bad argument #4 (expected table, got boolean)") + end) + + it("draws an image", function() + local win = helpers.with_window(7, 3, function() + nft.draw({ + { background = "aaaaa", foreground = "f000f", text = "Hello" }, + }, 2, 2) + end) + + expect(win.getLine(1)):eq(" ") + expect({ win.getLine(2) }):same { " Hello ", "0f000f0", "faaaaaf" } + expect(win.getLine(3)):eq(" ") + end) + + it("draws an image to a custom redirect", function() + local win = window.create(term.current(), 1, 1, 5, 1, false) + nft.draw({ + { background = "aaaaa", foreground = "f000f", text = "Hello" }, + }, 1, 1, win) + + expect({ win.getLine(1) }):same { "Hello", "f000f", "aaaaa" } + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua b/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua new file mode 100644 index 000000000..0832a5715 --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua @@ -0,0 +1,228 @@ +local with_window = require "test_helpers".with_window + +describe("cc.pretty", function() + local pp = require("cc.pretty") + + describe("text", function() + it("is constant for the empty string", function() + expect(pp.text("")):eq(pp.empty) + end) + + it("is constant for a space", function() + expect(pp.text(" ")):eq(pp.space) + end) + + it("is constant for a newline", function() + expect(pp.text("\n")):eq(pp.space_line) + end) + + it("validates arguments", function() + expect.error(pp.text, 123):eq("bad argument #1 (expected string, got number)") + expect.error(pp.text, "", ""):eq("bad argument #2 (expected number, got string)") + end) + + it("produces text documents", function() + expect(pp.text("a")):same({ tag = "text", text = "a" }) + expect(pp.text("a", colours.grey)):same({ tag = "text", text = "a", colour = colours.grey }) + end) + + it("splits lines", function() + expect(pp.text("a\nb")) + :same(pp.concat(pp.text("a"), pp.space_line, pp.text("b"))) + expect(pp.text("ab\ncd\nef")) + :same(pp.concat(pp.text("ab"), pp.space_line, pp.text("cd"), pp.space_line, pp.text("ef"))) + end) + + it("preserves empty lines", function() + expect(pp.text("a\n\nb")) + :same(pp.concat(pp.text("a"), pp.space_line, pp.space_line, pp.text("b"))) + expect(pp.text("\n\nb")) + :same(pp.concat(pp.space_line, pp.space_line, pp.text("b"))) + expect(pp.text("a\n\n")) + :same(pp.concat(pp.text("a"), pp.space_line, pp.space_line)) + end) + end) + + describe("concat", function() + it("returns empty with 0 arguments", function() + expect(pp.concat()):eq(pp.empty) + end) + + it("acts as the identity with 1 argument", function() + local x = pp.text("test") + expect(pp.concat(x)):eq(x) + end) + + it("coerces strings", function() + expect(pp.concat("a", "b")):same(pp.concat(pp.text("a"), pp.text("b"))) + end) + + it("validates arguments", function() + expect.error(pp.concat, 123):eq("bad argument #1 (expected document, got number)") + expect.error(pp.concat, "", {}):eq("bad argument #2 (expected document, got table)") + end) + + it("can be used as an operator", function() + local a, b = pp.text("a"), pp.text("b") + expect(pp.concat(a, b)):same(a .. b) + end) + end) + + describe("group", function() + it("is idempotent", function() + local x = pp.group(pp.text("a\nb")) + expect(pp.group(x)):eq(x) + end) + + it("does nothing for flat strings", function() + local x = pp.text("a") + expect(pp.group(x)):eq(x) + end) + end) + + -- Allows us to test + local function test_output(display) + it("displays the empty document", function() + expect(display(pp.empty)):same { "" } + end) + + it("displays a multiline string", function() + expect(display(pp.text("hello\nworld"))):same { + "hello", + "world", + } + end) + + it("displays a nested string", function() + expect(display(pp.nest(2, pp.concat("hello", pp.line, "world")))):same { + "hello", + " world", + } + end) + + it("displays a flattened group", function() + expect(display(pp.group(pp.concat("hello", pp.space_line, "world")))):same { + "hello world", + } + + expect(display(pp.group(pp.concat("hello", pp.line, "world")))):same { + "helloworld", + } + end) + + it("displays an expanded group", function() + expect(display(pp.group(pp.concat("hello darkness", pp.space_line, "my old friend")))):same { + "hello darkness", + "my old friend", + } + end) + + it("group removes nest", function() + expect(display(pp.group(pp.nest(2, pp.concat("hello", pp.space_line, "world"))))):same { + "hello world", + } + end) + end + + describe("write", function() + local function display(doc) + local w = with_window(20, 10, function() pp.write(doc) end) + local _, y = w.getCursorPos() + + local out = {} + for i = 1, y do out[i] = w.getLine(i):gsub("%s+$", "") end + return out + end + + test_output(display) + + it("wraps a long string", function() + expect(display(pp.text("hello world this is a long string which will wrap"))):same { + "hello world this is", + "a long string which", + "will wrap", + } + end) + end) + + describe("render", function() + local function display(doc) + local rendered = pp.render(doc, 20) + local n, lines = 1, {} + for line in (rendered .. "\n"):gmatch("([^\n]*)\n") do lines[n], n = line, n + 1 end + return lines + end + + test_output(display) + + it("does not wrap a long string", function() + expect(display(pp.text("hello world this is a long string which will wrap"))):same { + "hello world this is a long string which will wrap", + } + end) + end) + + describe("pretty", function() + -- We make use of "render" here, as it's considerably easier than checking against the actual structure. + -- However, it does also mean our tests are less unit-like. + local function pretty(x, width, options) return pp.render(pp.pretty(x, options), width) end + + describe("tables", function() + it("displays empty tables", function() + expect(pp.pretty({})):same(pp.text("{}")) + end) + + it("displays list-like tables", function() + expect(pretty({ 1, 2, 3 })):eq("{ 1, 2, 3 }") + end) + + it("displays mixed tables", function() + expect(pretty({ n = 3, 1, 2, 3 })):eq("{ 1, 2, 3, n = 3 }") + end) + + it("escapes keys", function() + expect(pretty({ ["and"] = 1, ["not that"] = 2 })):eq('{ ["and"] = 1, ["not that"] = 2 }') + end) + + it("sorts keys", function() + expect(pretty({ c = 1, b = 2, a = 3 })):eq('{ a = 3, b = 2, c = 1 }') + end) + + it("groups tables", function() + expect(pretty({ 1, 2, 3 }, 4)):eq("{\n 1,\n 2,\n 3\n}") + end) + + it("handles sparse tables", function() + local tbl = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } + tbl[4] = nil + + expect(tostring(pp.pretty(tbl))):eq("{ 1, 2, 3, nil, 5, 6, 7, 8, 9, 10 }") + end) + end) + + it("shows numbers", function() + expect(pretty(123)):eq("123") + end) + + it("shows strings", function() + expect(pretty("hello\nworld")):eq('"hello\\nworld"') + end) + + describe("functions", function() + it("shows functions", function() + expect(pretty(pretty)):eq(tostring(pretty)) + end) + + it("shows function arguments", function() + local f = function(a, ...) end + expect(pretty(f, nil, { function_args = true })):eq(tostring(f) .. "(a, ...)") + end) + + it("shows the function source", function() + local f = function(a, ...) end + expect(pretty(f, nil, { function_source = true })) + :str_match("^function<.*pretty_spec%.lua:%d+>$") + end) + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua b/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua new file mode 100644 index 000000000..4ecc6056f --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua @@ -0,0 +1,65 @@ +describe("cc.shell.completion", function() + local c = require "cc.shell.completion" + + describe("dirOrFile", function() + it("completes both", function() + expect(c.dirOrFile(shell, "rom/")):same { + "apis/", "apis", "autorun/", "autorun", "help/", "help", + "modules/", "modules", "motd.txt", "programs/", "programs", "startup.lua", + } + end) + + it("adds a space", function() + expect(c.dirOrFile(shell, "rom/", nil, true)):same { + "apis/", "apis ", "autorun/", "autorun ", "help/", "help ", + "modules/", "modules ", "motd.txt ", "programs/", "programs ", "startup.lua ", + } + end) + end) + + describe("program", function() + it("completes programs", function() + expect(c.program(shell, "rom/")):same { + "apis/", "autorun/", "help/", "modules/", "motd.txt", "programs/", "startup.lua", + } + end) + end) + + describe("programWithArgs", function() + it("completes program name", function() + shell.setCompletionFunction("rom/motd.txt", function() end) + expect(c.programWithArgs(shell, "rom/", { "rom/programs/shell.lua" }, 2)):same { + "apis/", "autorun/", "help/", "modules/", "motd.txt ", "programs/", "startup.lua", + } + end) + + it("completes program arguments", function() + expect(c.programWithArgs(shell, "", { "rom/programs/shell.lua", "pastebin" }, 2)):same { + "put ", "get ", "run ", + } + end) + + end) + + describe("build", function() + it("completes multiple arguments", function() + local spec = c.build( + function() return { "a", "b", "c" } end, + nil, + { c.choice, { "d", "e", "f" } } + ) + + expect(spec(shell, 1, "")):same { "a", "b", "c" } + expect(spec(shell, 2, "")):same(nil) + expect(spec(shell, 3, "")):same { "d", "e", "f" } + expect(spec(shell, 4, "")):same(nil) + end) + + it("supports variadic completions", function() + local spec = c.build({ function() return { "a", "b", "c" } end, many = true }) + + expect(spec(shell, 1, "")):same({ "a", "b", "c" }) + expect(spec(shell, 2, "")):same({ "a", "b", "c" }) + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/modules/cc/shell/require_spec.lua b/src/test/resources/test-rom/spec/modules/cc/shell/require_spec.lua new file mode 100644 index 000000000..721476f9d --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/shell/require_spec.lua @@ -0,0 +1,79 @@ +describe("cc.require", function() + local r = require "cc.require" + local function mk() + local env = setmetatable({}, { __index = _ENV }) + env.require, env.package = r.make({}, "/test-files/modules") + return env.require, env.package + end + + local function setup(path, contents) + fs.delete("/test-files/modules") + io.open(path, "w"):write(contents):close() + end + + describe("require", function() + it("errors on recursive modules", function() + local require, package = mk() + package.preload.pkg = function() require "pkg" end + expect.error(require, "pkg"):eq("loop or previous error loading module 'pkg'") + end) + + it("supplies the current module name", function() + local require, package = mk() + package.preload.pkg = table.pack + expect(require("pkg")):same { n = 1, "pkg" } + end) + + it("returns true instead of nil", function() + local require, package = mk() + package.preload.pkg = function() return nil end + expect(require("pkg")):eq(true) + end) + + it("returns a constant value", function() + local require, package = mk() + package.preload.pkg = function() return {} end + expect(require("pkg")):eq(require("pkg")) + end) + + it("returns an error on not-found modules", function() + local require, package = mk() + package.path = "/?;/?.lua" + expect.error(require, "pkg"):eq( + "module 'pkg' not found:\n" .. + " no field package.preload['pkg']\n" .. + " no file '/pkg'\n" .. + " no file '/pkg.lua'") + end) + end) + + describe("the file loader", function() + local function get(path) + local require, package = mk() + if path then package.path = path end + return require + end + + it("works on absolute paths", function() + local require = get("/test-files/?.lua") + setup("test-files/some_module.lua", "return 123") + expect(require("some_module")):eq(123) + end) + + it("works on relative paths", function() + local require = get("?.lua") + setup("test-files/modules/some_module.lua", "return 123") + expect(require("some_module")):eq(123) + end) + + it("fails on syntax errors", function() + local require = get("?.lua") + setup("test-files/modules/some_module.lua", "1") + expect.error(require, "some_module"):str_match( + "^module 'some_module' not found:\n" .. + " no field package.preload%['some_module'%]\n" .. + " [^:]*some_module.lua:1: unexpected symbol near '1'$" + ) + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/modules/cc/strings_spec.lua b/src/test/resources/test-rom/spec/modules/cc/strings_spec.lua new file mode 100644 index 000000000..900c6fe6f --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/strings_spec.lua @@ -0,0 +1,41 @@ +describe("cc.pretty", function() + local str = require("cc.strings") + + describe("wrap", function() + it("validates arguments", function() + str.wrap("test string is long") + str.wrap("test string is long", 11) + expect.error(str.wrap, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(str.wrap, "", false):eq("bad argument #2 (expected number, got boolean)") + end) + + it("wraps lines", function() + expect(str.wrap("test string is long")[1]):eq("test string is long") + + expect(str.wrap("test string is long", 15)[1]):eq("test string is ") + expect(str.wrap("test string is long", 15)[2]):eq("long") + + expect(str.wrap("test string is long", 12)[1]):eq("test string ") + expect(str.wrap("test string is long", 12)[2]):eq("is long") + + expect(str.wrap("test string is long", 11)[1]):eq("test string") + expect(str.wrap("test string is long", 11)[2]):eq("is long") + end) + end) + + describe("ensure_width", function() + it("validates arguments", function() + str.wrap("test string is long") + str.wrap("test string is long", 11) + expect.error(str.ensure_width, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(str.ensure_width, "", false):eq("bad argument #2 (expected number, got boolean)") + end) + + it("pads lines", function() + expect(str.ensure_width("test string is long", 25)):eq("test string is long ") + end) + it("truncates lines", function() + expect(str.ensure_width("test string is long", 15)):eq("test string is ") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/advanced/bg_spec.lua b/src/test/resources/test-rom/spec/programs/advanced/bg_spec.lua new file mode 100644 index 000000000..a53dc2f2d --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/advanced/bg_spec.lua @@ -0,0 +1,11 @@ +local capture = require "test_helpers".capture_program + +describe("The bg program", function() + it("opens a tab in the background", function() + local openTab = stub(shell, "openTab", function() return 12 end) + local switchTab = stub(shell, "switchTab") + capture(stub, "bg") + expect(openTab):called_with("shell") + expect(switchTab):called(0) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/advanced/fg_spec.lua b/src/test/resources/test-rom/spec/programs/advanced/fg_spec.lua new file mode 100644 index 000000000..8e5cc4f26 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/advanced/fg_spec.lua @@ -0,0 +1,11 @@ +local capture = require "test_helpers".capture_program + +describe("The fg program", function() + it("opens the shell in the foreground", function() + local openTab = stub(shell, "openTab", function() return 12 end) + local switchTab = stub(shell, "switchTab") + capture(stub, "fg") + expect(openTab):called_with("shell") + expect(switchTab):called_with(12) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua b/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua new file mode 100644 index 000000000..d0917c296 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua @@ -0,0 +1,30 @@ +describe("The multishell program", function() + describe("multishell.setFocus", function() + it("validates arguments", function() + multishell.setFocus(multishell.getFocus()) + expect.error(multishell.setFocus, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) + + describe("multishell.getTitle", function() + it("validates arguments", function() + multishell.getTitle(1) + expect.error(multishell.getTitle, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) + + describe("multishell.setTitle", function() + it("validates arguments", function() + multishell.setTitle(1, multishell.getTitle(1)) + expect.error(multishell.setTitle, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(multishell.setTitle, 1, nil):eq("bad argument #2 (expected string, got nil)") + end) + end) + + describe("multishell.launch", function() + it("validates arguments", function() + expect.error(multishell.launch, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(multishell.launch, _ENV, nil):eq("bad argument #2 (expected string, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/alias_spec.lua b/src/test/resources/test-rom/spec/programs/alias_spec.lua new file mode 100644 index 000000000..95a2c2556 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/alias_spec.lua @@ -0,0 +1,28 @@ +local capture = require "test_helpers".capture_program + +describe("The alias program", function() + it("displays its usage when given too many arguments", function() + expect(capture(stub, "alias a b c")) + :matches { ok = true, output = "Usage: alias \n", error = "" } + end) + + it("lists aliases", function() + local pagedTabulate = stub(textutils, "pagedTabulate", function(x) print(table.unpack(x)) end) + stub(shell, "aliases", function() return { cp = "copy" } end) + expect(capture(stub, "alias")) + :matches { ok = true, output = "cp:copy\n", error = "" } + expect(pagedTabulate):called_with_matching({ "cp:copy" }) + end) + + it("sets an alias", function() + local setAlias = stub(shell, "setAlias") + capture(stub, "alias test Hello") + expect(setAlias):called_with("test", "Hello") + end) + + it("clears an alias", function() + local clearAlias = stub(shell, "clearAlias") + capture(stub, "alias test") + expect(clearAlias):called_with("test") + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/cd_spec.lua b/src/test/resources/test-rom/spec/programs/cd_spec.lua new file mode 100644 index 000000000..348d62944 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/cd_spec.lua @@ -0,0 +1,19 @@ +local capture = require "test_helpers".capture_program + +describe("The cd program", function() + it("changes into a directory", function() + local setDir = stub(shell, "setDir") + capture(stub, "cd /rom/programs") + expect(setDir):called_with("rom/programs") + end) + + it("does not move into a non-existent directory", function() + expect(capture(stub, "cd /rom/nothing")) + :matches { ok = true, output = "Not a directory\n", error = "" } + end) + + it("displays the usage when given no arguments", function() + expect(capture(stub, "cd")) + :matches { ok = true, output = "Usage: cd \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/clear_spec.lua b/src/test/resources/test-rom/spec/programs/clear_spec.lua new file mode 100644 index 000000000..f339c83ce --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/clear_spec.lua @@ -0,0 +1,13 @@ +local capture = require "test_helpers".capture_program + +describe("The clear program", function() + it("clears the screen", function() + local clear = stub(term, "clear") + local setCursorPos = stub(term, "setCursorPos") + + capture(stub, "clear") + + expect(clear):called(1) + expect(setCursorPos):called_with(1, 1) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/command/commands_spec.lua b/src/test/resources/test-rom/spec/programs/command/commands_spec.lua new file mode 100644 index 000000000..6c9d87cdc --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/command/commands_spec.lua @@ -0,0 +1,20 @@ +local capture = require "test_helpers".capture_program + +describe("The commands program", function() + it("displays an error without the commands api", function() + stub(_G, "commands", nil) + expect(capture(stub, "/rom/programs/command/commands.lua")) + :matches { ok = true, output = "", error = "Requires a Command Computer.\n" } + end) + + it("lists commands", function() + local pagedTabulate = stub(textutils, "pagedTabulate", function(x) print(table.unpack(x)) end) + stub(_G, "commands", { + list = function() return { "computercraft" } end, + }) + + expect(capture(stub, "/rom/programs/command/commands.lua")) + :matches { ok = true, output = "Available commands:\ncomputercraft\n", error = "" } + expect(pagedTabulate):called_with_matching({ "computercraft" }) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/command/exec_spec.lua b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua new file mode 100644 index 000000000..f5eecd3d3 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua @@ -0,0 +1,33 @@ +local capture = require "test_helpers".capture_program + +describe("The exec program", function() + it("displays an error without the commands api", function() + stub(_G, "commands", nil) + expect(capture(stub, "/rom/programs/command/exec.lua")) + :matches { ok = true, output = "", error = "Requires a Command Computer.\n" } + end) + + it("displays its usage when given no argument", function() + stub(_G, "commands", {}) + expect(capture(stub, "/rom/programs/command/exec.lua")) + :matches { ok = true, output = "", error = "Usage: /rom/programs/command/exec.lua \n" } + end) + + it("runs a command", function() + stub(_G, "commands", { + exec = function() return true, { "Hello World!" } end, + }) + + expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) + :matches { ok = true, output = "Success\nHello World!\n", error = "" } + end) + + it("reports command failures", function() + stub(_G, "commands", { + exec = function() return false, { "Hello World!" } end, + }) + + expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) + :matches { ok = true, output = "Hello World!\n", error = "Failed\n" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/copy_spec.lua b/src/test/resources/test-rom/spec/programs/copy_spec.lua new file mode 100644 index 000000000..5bcdda8b0 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/copy_spec.lua @@ -0,0 +1,40 @@ +local capture = require "test_helpers".capture_program + +describe("The copy program", function() + local function touch(file) + io.open(file, "w"):close() + end + + it("copies a file", function() + touch("/test-files/copy/a.txt") + + shell.run("copy /test-files/copy/a.txt /test-files/copy/b.txt") + + expect(fs.exists("/test-files/copy/a.txt")):eq(true) + expect(fs.exists("/test-files/copy/b.txt")):eq(true) + end) + + it("fails when copying a non-existent file", function() + expect(capture(stub, "copy nothing destination")) + :matches { ok = true, output = "", error = "No matching files\n" } + end) + + it("fails when overwriting an existing file", function() + touch("/test-files/copy/c.txt") + + expect(capture(stub, "copy /test-files/copy/c.txt /test-files/copy/c.txt")) + :matches { ok = true, output = "", error = "Destination exists\n" } + end) + + it("fails when copying into read-only locations", function() + touch("/test-files/copy/d.txt") + + expect(capture(stub, "copy /test-files/copy/d.txt /rom/test.txt")) + :matches { ok = true, output = "", error = "Destination is read-only\n" } + end) + + it("displays the usage when given no arguments", function() + expect(capture(stub, "copy")) + :matches { ok = true, output = "Usage: copy \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/delete_spec.lua b/src/test/resources/test-rom/spec/programs/delete_spec.lua new file mode 100644 index 000000000..18a01c5c0 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/delete_spec.lua @@ -0,0 +1,60 @@ +local capture = require "test_helpers".capture_program + +describe("The rm program", function() + local function touch(file) + io.open(file, "w"):close() + end + + it("deletes one file", function() + touch("/test-files/a.txt") + + shell.run("rm /test-files/a.txt") + + expect(fs.exists("/test-files/a.txt")):eq(false) + end) + + it("deletes many files", function() + touch("/test-files/a.txt") + touch("/test-files/b.txt") + touch("/test-files/c.txt") + + shell.run("rm /test-files/a.txt /test-files/b.txt") + + expect(fs.exists("/test-files/a.txt")):eq(false) + expect(fs.exists("/test-files/b.txt")):eq(false) + expect(fs.exists("/test-files/c.txt")):eq(true) + end) + + it("deletes a glob", function() + touch("/test-files/a.txt") + touch("/test-files/b.txt") + + shell.run("rm /test-files/*.txt") + + expect(fs.exists("/test-files/a.txt")):eq(false) + expect(fs.exists("/test-files/b.txt")):eq(false) + end) + + it("displays the usage with no arguments", function() + expect(capture(stub, "rm")) + :matches { ok = true, output = "Usage: rm \n", error = "" } + end) + + it("errors when trying to delete a read-only file", function() + expect(capture(stub, "rm /rom/startup.lua")) + :matches { ok = true, output = "", error = "Cannot delete read-only file /rom/startup.lua\n" } + end) + + it("errors when trying to delete the root mount", function() + expect(capture(stub, "rm /")):matches { + ok = true, + output = "To delete its contents run rm /*\n", + error = "Cannot delete mount /\n", + } + end) + + it("errors when a glob fails to match", function() + expect(capture(stub, "rm", "never-existed")) + :matches { ok = true, output = "", error = "never-existed: No matching files\n" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/drive_spec.lua b/src/test/resources/test-rom/spec/programs/drive_spec.lua new file mode 100644 index 000000000..d175a60f7 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/drive_spec.lua @@ -0,0 +1,16 @@ +local capture = require "test_helpers".capture_program + +describe("The drive program", function() + it("run the program", function() + local getFreeSpace = stub(fs, "getFreeSpace", function() return 1234e4 end) + + expect(capture(stub, "drive")) + :matches { ok = true, output = "hdd (12.3MB remaining)\n", error = "" } + expect(getFreeSpace):called(1):called_with("") + end) + + it("fails on a non-existent path", function() + expect(capture(stub, "drive /rom/nothing")) + :matches { ok = true, output = "No such path\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/edit_spec.lua b/src/test/resources/test-rom/spec/programs/edit_spec.lua new file mode 100644 index 000000000..e58938e23 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/edit_spec.lua @@ -0,0 +1,9 @@ +local capture = require "test_helpers".capture_program + +describe("The edit program", function() + + it("displays its usage when given no argument", function() + expect(capture(stub, "edit")) + :matches { ok = true, output = "Usage: edit \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/eject_spec.lua b/src/test/resources/test-rom/spec/programs/eject_spec.lua new file mode 100644 index 000000000..e524a8625 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/eject_spec.lua @@ -0,0 +1,13 @@ +local capture = require "test_helpers".capture_program + +describe("The eject program", function() + it("displays its usage when given no argument", function() + expect(capture(stub, "eject")) + :matches { ok = true, output = "Usage: eject \n", error = "" } + end) + + it("fails when trying to eject a non-drive", function() + expect(capture(stub, "eject /rom")) + :matches { ok = true, output = "Nothing in /rom drive\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/exit_spec.lua b/src/test/resources/test-rom/spec/programs/exit_spec.lua new file mode 100644 index 000000000..301461087 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/exit_spec.lua @@ -0,0 +1,9 @@ +local capture = require "test_helpers".capture_program + +describe("The exit program", function() + it("exits the shell", function() + local exit = stub(shell, "exit") + expect(capture(stub, "exit")):matches { ok = true, combined = "" } + expect(exit):called(1) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/fun/advanced/paint_spec.lua b/src/test/resources/test-rom/spec/programs/fun/advanced/paint_spec.lua new file mode 100644 index 000000000..086404add --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/fun/advanced/paint_spec.lua @@ -0,0 +1,8 @@ +local capture = require "test_helpers".capture_program + +describe("The paint program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "paint")) + :matches { ok = true, output = "Usage: paint \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/fun/dj_spec.lua b/src/test/resources/test-rom/spec/programs/fun/dj_spec.lua new file mode 100644 index 000000000..4464d4e8c --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/fun/dj_spec.lua @@ -0,0 +1,13 @@ +local capture = require "test_helpers".capture_program + +describe("The dj program", function() + it("displays its usage when given too many arguments", function() + expect(capture(stub, "dj a b c")) + :matches { ok = true, output = "Usages:\ndj play\ndj play \ndj stop\n", error = "" } + end) + + it("fails when no disks are present", function() + expect(capture(stub, "dj")) + :matches { ok = true, output = "No Music Discs in attached disk drives\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/fun/hello_spec.lua b/src/test/resources/test-rom/spec/programs/fun/hello_spec.lua new file mode 100644 index 000000000..25db085bc --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/fun/hello_spec.lua @@ -0,0 +1,10 @@ +local capture = require "test_helpers".capture_program + +describe("The hello program", function() + it("says hello", function() + local slowPrint = stub(textutils, "slowPrint", function(...) return print(...) end) + expect(capture(stub, "hello")) + :matches { ok = true, output = "Hello World!\n", error = "" } + expect(slowPrint):called(1) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/gps_spec.lua b/src/test/resources/test-rom/spec/programs/gps_spec.lua new file mode 100644 index 000000000..245f259c9 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/gps_spec.lua @@ -0,0 +1,23 @@ +local capture = require "test_helpers".capture_program + +describe("The gps program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "gps")) + :matches { ok = true, output = "Usages:\ngps host\ngps host \ngps locate\n", error = "" } + end) + + it("fails on a pocket computer", function() + stub(_G, "pocket", {}) + + expect(capture(stub, "gps host")) + :matches { ok = true, output = "GPS Hosts must be stationary\n", error = "" } + end) + + it("can locate the computer", function() + local locate = stub(gps, "locate", function() print("Some debugging information.") end) + + expect(capture(stub, "gps locate")) + :matches { ok = true, output = "Some debugging information.\n", error = "" } + expect(locate):called_with(2, true) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/help_spec.lua b/src/test/resources/test-rom/spec/programs/help_spec.lua new file mode 100644 index 000000000..35ce021b4 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/help_spec.lua @@ -0,0 +1,8 @@ +local capture = require "test_helpers".capture_program + +describe("The help program", function() + it("errors when there is no such help file", function() + expect(capture(stub, "help nothing")) + :matches { ok = true, error = "No help available\n", output = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua new file mode 100644 index 000000000..192ba7007 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua @@ -0,0 +1,77 @@ +local capture = require "test_helpers".capture_program + +describe("The pastebin program", function() + local function setup_request() + stub(_G, "http", { + checkURL = function() + return true + end, + get = function() + return { + readAll = function() + return [[print("Hello", ...)]] + end, + close = function() + end, + getResponseHeaders = function() + local tHeader = {} + tHeader["Content-Type"] = "text/plain; charset=utf-8" + return tHeader + end, + } + end, + post = function() + return { + readAll = function() + return "https://pastebin.com/abcde" + end, + close = function() + end, + } + end, + }) + end + + it("downloads one file", function() + setup_request() + capture(stub, "pastebin", "get", "abcde", "testdown") + + expect(fs.exists("/testdown")):eq(true) + end) + + it("runs a program from the internet", function() + setup_request() + + expect(capture(stub, "pastebin", "run", "abcde", "a", "b", "c")) + :matches { ok = true, output = "Connecting to pastebin.com... Success.\nHello a b c\n", error = "" } + end) + + it("upload a program to pastebin", function() + setup_request() + + local file = fs.open("testup", "w") + file.close() + + expect(capture(stub, "pastebin", "put", "testup")) + :matches { ok = true, output = "Connecting to pastebin.com... Success.\nUploaded as https://pastebin.com/abcde\nRun \"pastebin get abcde\" to download anywhere\n", error = "" } + end) + + it("upload a not existing program to pastebin", function() + setup_request() + + expect(capture(stub, "pastebin", "put", "nothing")) + :matches { ok = true, output = "No such file\n", error = "" } + end) + + it("displays its usage when given no arguments", function() + setup_request() + + expect(capture(stub, "pastebin")) + :matches { ok = true, output = "Usages:\npastebin put \npastebin get \npastebin run \n", error = "" } + end) + + it("can be completed", function() + local complete = shell.getCompletionInfo()["rom/programs/http/pastebin.lua"].fnComplete + expect(complete(shell, 1, "", {})):same { "put ", "get ", "run " } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/http/wget_spec.lua b/src/test/resources/test-rom/spec/programs/http/wget_spec.lua new file mode 100644 index 000000000..c4b28dc53 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/http/wget_spec.lua @@ -0,0 +1,78 @@ +local capture = require "test_helpers".capture_program + +describe("The wget program", function() + local default_contents = [[print("Hello", ...)]] + local function setup_request(contents) + stub(_G, "http", { + checkURL = function() + return true + end, + get = function() + return { + readAll = function() + return contents + end, + close = function() + end, + } + end, + }) + end + + it("downloads one file", function() + fs.delete("/example.com") + setup_request(default_contents) + + capture(stub, "wget", "https://example.com") + + expect(fs.exists("/example.com")):eq(true) + end) + + it("downloads one file with given filename", function() + fs.delete("/test-files/download") + setup_request(default_contents) + + capture(stub, "wget", "https://example.com /test-files/download") + + expect(fs.exists("/test-files/download")):eq(true) + end) + + it("downloads empty files", function() + fs.delete("/test-files/download") + setup_request(nil) + + capture(stub, "wget", "https://example.com", "/test-files/download") + + expect(fs.exists("/test-files/download")):eq(true) + expect(fs.getSize("/test-files/download")):eq(0) + end) + + it("cannot save to rom", function() + setup_request(default_contents) + + expect(capture(stub, "wget", "https://example.com", "/rom/a-file.txt")):matches { + ok = true, + output = "Connecting to https://example.com... Success.\n", + error = "Cannot save file: /rom/a-file.txt: Access denied\n", + } + end) + + it("runs a program from the internet", function() + setup_request(default_contents) + + expect(capture(stub, "wget", "run", "http://test.com", "a", "b", "c")) + :matches { ok = true, output = "Connecting to http://test.com... Success.\nHello a b c\n", error = "" } + end) + + it("displays its usage when given no arguments", function() + setup_request(default_contents) + + expect(capture(stub, "wget")) + :matches { ok = true, output = "Usage:\nwget [filename]\nwget run \n", error = "" } + end) + + it("can be completed", function() + local complete = shell.getCompletionInfo()["rom/programs/http/wget.lua"].fnComplete + expect(complete(shell, 1, "", {})):same { "run " } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/id_spec.lua b/src/test/resources/test-rom/spec/programs/id_spec.lua new file mode 100644 index 000000000..7c5d47da7 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/id_spec.lua @@ -0,0 +1,11 @@ +local capture = require "test_helpers".capture_program + +describe("The id program", function() + + it("displays computer id", function() + local id = os.getComputerID() + + expect(capture(stub, "id")) + :matches { ok = true, output = "This is computer #" .. id .. "\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/label_spec.lua b/src/test/resources/test-rom/spec/programs/label_spec.lua new file mode 100644 index 000000000..5762f8fbe --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/label_spec.lua @@ -0,0 +1,34 @@ +local capture = require "test_helpers".capture_program + +describe("The label program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "label")) + :matches { ok = true, output = "Usages:\nlabel get\nlabel get \nlabel set \nlabel set \nlabel clear\nlabel clear \n", error = "" } + end) + + describe("displays the computer's label", function() + it("when it is not labelled", function() + stub(os, "getComputerLabel", function() return nil end) + expect(capture(stub, "label get")) + :matches { ok = true, output = "No Computer label\n", error = "" } + end) + + it("when it is labelled", function() + stub(os, "getComputerLabel", function() return "Test" end) + expect(capture(stub, "label get")) + :matches { ok = true, output = "Computer label is \"Test\"\n", error = "" } + end) + end) + + it("sets the computer's label", function() + local setComputerLabel = stub(os, "setComputerLabel") + capture(stub, "label set Test") + expect(setComputerLabel):called_with("Test") + end) + + it("clears the computer's label", function() + local setComputerLabel = stub(os, "setComputerLabel") + capture(stub, "label clear") + expect(setComputerLabel):called_with(nil) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/list_spec.lua b/src/test/resources/test-rom/spec/programs/list_spec.lua new file mode 100644 index 000000000..f9f5f0b0b --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/list_spec.lua @@ -0,0 +1,22 @@ +local capture = require "test_helpers".capture_program + +describe("The list program", function() + it("lists files", function() + local pagedTabulate = stub(textutils, "pagedTabulate") + capture(stub, "list /rom") + expect(pagedTabulate):called_with_matching( + colors.green, { "apis", "autorun", "help", "modules", "programs" }, + colors.white, { "motd.txt", "startup.lua" } + ) + end) + + it("fails on a non-existent directory", function() + expect(capture(stub, "list /rom/nothing")) + :matches { ok = true, output = "", error = "Not a directory\n" } + end) + + it("fails on a file", function() + expect(capture(stub, "list /rom/startup.lua")) + :matches { ok = true, output = "", error = "Not a directory\n" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/mkdir_spec.lua b/src/test/resources/test-rom/spec/programs/mkdir_spec.lua new file mode 100644 index 000000000..fb7327519 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/mkdir_spec.lua @@ -0,0 +1,29 @@ +describe("The mkdir program", function() + it("creates a directory", function() + fs.delete("/test-files") + + shell.run("mkdir /test-files/a") + + expect(fs.isDir("/test-files/a")):eq(true) + end) + + it("creates many directories", function() + fs.delete("/test-files") + + shell.run("mkdir /test-files/a /test-files/b") + + expect(fs.isDir("/test-files/a")):eq(true) + expect(fs.isDir("/test-files/b")):eq(true) + end) + + it("can be completed", function() + fs.delete("/test-files") + fs.makeDir("/test-files/a") + fs.makeDir("/test-files/b") + io.open("/test-files.a.txt", "w"):close() + + local complete = shell.getCompletionInfo()["rom/programs/mkdir.lua"].fnComplete + expect(complete(shell, 1, "/test-files/", {})):same { "a/", "a", "b/", "b" } + expect(complete(shell, 2, "/test-files/", { "/" })):same { "a/", "a", "b/", "b" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/monitor_spec.lua b/src/test/resources/test-rom/spec/programs/monitor_spec.lua new file mode 100644 index 000000000..ea7c8bbd7 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/monitor_spec.lua @@ -0,0 +1,44 @@ +local capture = require "test_helpers".capture_program + +describe("The monitor program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "monitor")) + :matches { + ok = true, + output = + "Usage:\n" .. + " monitor \n" .. + " monitor scale \n", + error = "", + } + end) + + it("changes the text scale with the scale command", function() + local r = 1 + stub(peripheral, "call", function(s, f, t) r = t end) + stub(peripheral, "getType", function() return "monitor" end) + expect(capture(stub, "monitor", "scale", "left", "0.5")) + :matches { ok = true, output = "", error = "" } + expect(r):equals(0.5) + end) + + it("displays correct error messages", function() + local r = 1 + stub(peripheral, "call", function(s, f, t) r = t end) + stub(peripheral, "getType", function(side) return side == "left" and "monitor" or nil end) + expect(capture(stub, "monitor", "scale", "left")) + :matches { + ok = true, + output = + "Usage:\n" .. + " monitor \n" .. + " monitor scale \n", + error = "", + } + expect(capture(stub, "monitor", "scale", "top", "0.5")) + :matches { ok = true, output = "No monitor named top\n", error = "" } + expect(capture(stub, "monitor", "scale", "left", "aaa")) + :matches { ok = true, output = "Invalid scale: aaa\n", error = "" } + expect(r):equals(1) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/motd_spec.lua b/src/test/resources/test-rom/spec/programs/motd_spec.lua new file mode 100644 index 000000000..47fcfccd3 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/motd_spec.lua @@ -0,0 +1,42 @@ +local capture = require "test_helpers".capture_program + +describe("The motd program", function() + local function setup_date(day, month) + stub(os, "date", function() return { day = day, month = month } end) + end + + it("displays MOTD", function() + setup_date(0, 0) + local file = fs.open("/motd_check.txt", "w") + file.write("Hello World!") + file.close() + settings.set("motd.path", "/motd_check.txt") + + expect(capture(stub, "motd")) + :matches { ok = true, output = "Hello World!\n", error = "" } + end) + + it("displays date-specific MOTD (1 Jan)", function() + setup_date(1, 1) + expect(capture(stub, "motd")) + :matches { ok = true, output = "Happy new year!\n", error = "" } + end) + + it("displays date-specific MOTD (28 Apr)", function() + setup_date(28, 4) + expect(capture(stub, "motd")) + :matches { ok = true, output = "Ed Balls\n", error = "" } + end) + + it("displays date-specific MOTD (31 Oct)", function() + setup_date(31, 10) + expect(capture(stub, "motd")) + :matches { ok = true, output = "OOoooOOOoooo! Spooky!\n", error = "" } + end) + + it("displays date-specific MOTD (24 Dec)", function() + setup_date(24, 12) + expect(capture(stub, "motd")) + :matches { ok = true, output = "Merry X-mas!\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/move_spec.lua b/src/test/resources/test-rom/spec/programs/move_spec.lua new file mode 100644 index 000000000..dcc156362 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/move_spec.lua @@ -0,0 +1,74 @@ +local capture = require "test_helpers".capture_program + +describe("The move program", function() + local function cleanup() fs.delete("/test-files/move") end + local function touch(file) + io.open(file, "w"):close() + end + + it("move a file", function() + cleanup() + touch("/test-files/move/a.txt") + + shell.run("move /test-files/move/a.txt /test-files/move/b.txt") + + expect(fs.exists("/test-files/move/a.txt")):eq(false) + expect(fs.exists("/test-files/move/b.txt")):eq(true) + end) + + it("moves a file to a directory", function() + cleanup() + touch("/test-files/move/a.txt") + fs.makeDir("/test-files/move/a") + + expect(capture(stub, "move /test-files/move/a.txt /test-files/move/a")) + :matches { ok = true } + + expect(fs.exists("/test-files/move/a.txt")):eq(false) + expect(fs.exists("/test-files/move/a/a.txt")):eq(true) + end) + + it("fails when moving a file which doesn't exist", function() + expect(capture(stub, "move nothing destination")) + :matches { ok = true, output = "", error = "No matching files\n" } + end) + + it("fails when overwriting an existing file", function() + cleanup() + touch("/test-files/move/a.txt") + + expect(capture(stub, "move /test-files/move/a.txt /test-files/move/a.txt")) + :matches { ok = true, output = "", error = "Destination exists\n" } + end) + + it("fails when moving to read-only locations", function() + cleanup() + touch("/test-files/move/a.txt") + + expect(capture(stub, "move /test-files/move/a.txt /rom/test.txt")) + :matches { ok = true, output = "", error = "Destination is read-only\n" } + end) + + it("fails when moving from read-only locations", function() + expect(capture(stub, "move /rom/startup.lua /test-files/move/not-exist.txt")) + :matches { ok = true, output = "", error = "Cannot move read-only file /rom/startup.lua\n" } + end) + + it("fails when moving mounts", function() + expect(capture(stub, "move /rom /test-files/move/rom")) + :matches { ok = true, output = "", error = "Cannot move mount /rom\n" } + end) + + it("fails when moving a file multiple times", function() + cleanup() + touch("/test-files/move/a.txt") + touch("/test-files/move/b.txt") + expect(capture(stub, "move /test-files/move/*.txt /test-files/move/c.txt")) + :matches { ok = true, output = "", error = "Cannot overwrite file multiple times\n" } + end) + + it("displays the usage with no arguments", function() + expect(capture(stub, "move")) + :matches { ok = true, output = "Usage: move \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/peripherals_spec.lua b/src/test/resources/test-rom/spec/programs/peripherals_spec.lua new file mode 100644 index 000000000..68762e79f --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/peripherals_spec.lua @@ -0,0 +1,9 @@ +local capture = require "test_helpers".capture_program + +describe("The peripherals program", function() + it("says when there are no peripherals", function() + stub(peripheral, 'getNames', function() return {} end) + expect(capture(stub, "peripherals")) + :matches { ok = true, output = "Attached Peripherals:\nNone\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua b/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua new file mode 100644 index 000000000..32144051b --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua @@ -0,0 +1,27 @@ +local capture = require "test_helpers".capture_program + +describe("The pocket equip program", function() + it("errors when not a pocket computer", function() + stub(_G, "pocket", nil) + expect(capture(stub, "/rom/programs/pocket/equip.lua")) + :matches { ok = true, output = "", error = "Requires a Pocket Computer\n" } + end) + + it("can equip an upgrade", function() + stub(_G, "pocket", { + equipBack = function() return true end, + }) + + expect(capture(stub, "/rom/programs/pocket/equip.lua")) + :matches { ok = true, output = "Item equipped\n", error = "" } + end) + + it("handles when an upgrade cannot be equipped", function() + stub(_G, "pocket", { + equipBack = function() return false, "Cannot equip this item." end, + }) + + expect(capture(stub, "/rom/programs/pocket/equip.lua")) + :matches { ok = true, output = "", error = "Cannot equip this item.\n" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua b/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua new file mode 100644 index 000000000..9cb0f7481 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua @@ -0,0 +1,27 @@ +local capture = require "test_helpers".capture_program + +describe("The pocket unequip program", function() + it("errors when not a pocket computer", function() + stub(_G, "pocket", nil) + expect(capture(stub, "/rom/programs/pocket/unequip.lua")) + :matches { ok = true, output = "", error = "Requires a Pocket Computer\n" } + end) + + it("unequips an upgrade", function() + stub(_G, "pocket", { + unequipBack = function() return true end, + }) + + expect(capture(stub, "/rom/programs/pocket/unequip.lua")) + :matches { ok = true, output = "Item unequipped\n", error = "" } + end) + + it("handles when an upgrade cannot be equipped", function() + stub(_G, "pocket", { + unequipBack = function() return false, "Nothing to remove." end, + }) + + expect(capture(stub, "/rom/programs/pocket/unequip.lua")) + :matches { ok = true, output = "", error = "Nothing to remove.\n" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/programs_spec.lua b/src/test/resources/test-rom/spec/programs/programs_spec.lua new file mode 100644 index 000000000..8f19bc83e --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/programs_spec.lua @@ -0,0 +1,14 @@ +local capture = require "test_helpers".capture_program + +describe("The programs program", function() + it("list programs", function() + local programs = stub(shell, "programs", function() return { "some", "programs" } end) + local pagedTabulate = stub(textutils, "pagedTabulate", function(x) print(table.unpack(x)) end) + + expect(capture(stub, "/rom/programs/programs.lua")) + :matches { ok = true, output = "some programs\n", error = "" } + + expect(programs):called_with(false) + expect(pagedTabulate):called_with_matching({ "some", "programs" }) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/reboot_spec.lua b/src/test/resources/test-rom/spec/programs/reboot_spec.lua new file mode 100644 index 000000000..d2a877d9d --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/reboot_spec.lua @@ -0,0 +1,14 @@ +local capture = require "test_helpers".capture_program + +describe("The reboot program", function() + it("sleeps and then reboots", function() + local sleep = stub(_G, "sleep") + local reboot = stub(os, "reboot") + + expect(capture(stub, "reboot")) + :matches { ok = true, output = "Goodbye\n", error = "" } + + expect(sleep):called_with(1) + expect(reboot):called() + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/redstone_spec.lua b/src/test/resources/test-rom/spec/programs/redstone_spec.lua new file mode 100644 index 000000000..fc687ac7e --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/redstone_spec.lua @@ -0,0 +1,8 @@ +local capture = require "test_helpers".capture_program + +describe("The redstone program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "redstone")) + :matches { ok = true, output = "Usages:\nredstone probe\nredstone set \nredstone set \nredstone pulse \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/rename_spec.lua b/src/test/resources/test-rom/spec/programs/rename_spec.lua new file mode 100644 index 000000000..437e940d3 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/rename_spec.lua @@ -0,0 +1,50 @@ +local capture = require "test_helpers".capture_program + +describe("The rename program", function() + local function touch(file) + io.open(file, "w"):close() + end + + it("can rename a file", function() + touch("/test-files/rename/a.txt") + + shell.run("rename /test-files/rename/a.txt /test-files/rename/b.txt") + + expect(fs.exists("/test-files/rename/a.txt")):eq(false) + expect(fs.exists("/test-files/rename/b.txt")):eq(true) + end) + + it("fails when renaming a file which doesn't exist", function() + expect(capture(stub, "rename nothing destination")) + :matches { ok = true, output = "", error = "No matching files\n" } + end) + + it("fails when overwriting an existing file", function() + touch("/test-files/rename/c.txt") + + expect(capture(stub, "rename /test-files/rename/c.txt /test-files/rename/c.txt")) + :matches { ok = true, output = "", error = "Destination exists\n" } + end) + + it("fails when renaming to read-only locations", function() + touch("/test-files/rename/d.txt") + + expect(capture(stub, "rename /test-files/rename/d.txt /rom/test.txt")) + :matches { ok = true, output = "", error = "Destination is read-only\n" } + end) + + it("fails when renaming from read-only locations", function() + expect(capture(stub, "rename /rom/startup.lua /test-files/rename/d.txt")) + :matches { ok = true, output = "", error = "Source is read-only\n" } + end) + + it("fails when renaming mounts", function() + expect(capture(stub, "rename /rom /test-files/rename/rom")) + :matches { ok = true, output = "", error = "Can't rename mounts\n" } + end) + + it("displays the usage when given no arguments", function() + expect(capture(stub, "rename")) + :matches { ok = true, output = "Usage: rename \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/set_spec.lua b/src/test/resources/test-rom/spec/programs/set_spec.lua new file mode 100644 index 000000000..8d74d951e --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/set_spec.lua @@ -0,0 +1,59 @@ +local capture = require "test_helpers".capture_program + +describe("The set program", function() + local function setup() + local set = setmetatable({}, { __index = _G }) + loadfile("/rom/apis/settings.lua", set)() + stub(_G, "settings", set) + + settings.set("test", "Hello World!") + settings.define("test.defined", { default = 456, description = "A description", type = "number" }) + end + + it("displays all settings", function() + setup() + + expect(capture(stub, "set")) + :matches { ok = true, output = '"test" is "Hello World!"\n"test.defined" is 456\n', error = "" } + end) + + it("displays a single setting", function() + setup() + + expect(capture(stub, "set test")) + :matches { ok = true, output = 'test is "Hello World!"\n', error = "" } + end) + + it("displays a single setting with description", function() + setup() + + expect(capture(stub, "set test")) + :matches { ok = true, output = 'test is "Hello World!"\n', error = "" } + end) + + it("displays a changed setting with description", function() + setup() + + settings.set("test.defined", 123) + expect(capture(stub, "set test.defined")) + :matches { ok = true, output = 'test.defined is 123 (default is 456)\nA description\n', error = "" } + end) + + it("set a setting", function() + setup() + + expect(capture(stub, "set test Hello")) + :matches { ok = true, output = '"test" set to "Hello"\n', error = "" } + + expect(settings.get("test")):eq("Hello") + end) + + it("checks the type of a setting", function() + setup() + + expect(capture(stub, "set test.defined Hello")) + :matches { ok = true, output = "", error = '"Hello" is not a valid number.\n' } + expect(capture(stub, "set test.defined 456")) + :matches { ok = true, output = '"test.defined" set to 456\n', error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/shell_spec.lua b/src/test/resources/test-rom/spec/programs/shell_spec.lua new file mode 100644 index 000000000..fae7b85d1 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/shell_spec.lua @@ -0,0 +1,104 @@ +describe("The shell", function() + describe("require", function() + it("validates arguments", function() + require("math") + expect.error(require, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.execute", function() + it("parses in arguments verbatim", function() + shell.execute("/test-rom/data/dump-args", "arg1", "arg 2") + + local args = _G.__arg + _G.__arg = nil + + expect(args):same { [0] = "/test-rom/data/dump-args", "arg1", "arg 2" } + end) + end) + + describe("shell.run", function() + it("tokenises the arguments", function() + shell.run("/test-rom/data/dump-args", "arg1", "arg 2") + + local args = _G.__arg + _G.__arg = nil + + expect(args):same { [0] = "/test-rom/data/dump-args", "arg1", "arg", "2" } + end) + end) + + describe("shell.setDir", function() + it("validates arguments", function() + shell.setDir(shell.dir()) + expect.error(shell.setDir, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("not existing directory", function() + expect.error(shell.setDir, "/rom/nothing"):eq("Not a directory") + end) + end) + + describe("shell.setPath", function() + it("validates arguments", function() + shell.setPath(shell.path()) + expect.error(shell.setPath, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.resolve", function() + it("validates arguments", function() + shell.resolve("") + expect.error(shell.resolve, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.resolveProgram", function() + it("validates arguments", function() + shell.resolveProgram("ls") + expect.error(shell.resolveProgram, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.complete", function() + it("validates arguments", function() + shell.complete("ls") + expect.error(shell.complete, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.setCompletionFunction", function() + it("validates arguments", function() + expect.error(shell.setCompletionFunction, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(shell.setCompletionFunction, "", nil):eq("bad argument #2 (expected function, got nil)") + end) + end) + + describe("shell.setCompletionFunction", function() + it("validates arguments", function() + expect.error(shell.setCompletionFunction, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(shell.setCompletionFunction, "", nil):eq("bad argument #2 (expected function, got nil)") + end) + end) + + describe("shell.setAlias", function() + it("validates arguments", function() + shell.setAlias("sl", "ls") + expect.error(shell.setAlias, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(shell.setAlias, "", nil):eq("bad argument #2 (expected string, got nil)") + end) + end) + + describe("shell.clearAlias", function() + it("validates arguments", function() + shell.clearAlias("sl") + expect.error(shell.clearAlias, nil):eq("bad argument #1 (expected string, got nil)") + end) + end) + + describe("shell.switchTab", function() + it("validates arguments", function() + expect.error(shell.switchTab, nil):eq("bad argument #1 (expected number, got nil)") + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/shutdown_spec.lua b/src/test/resources/test-rom/spec/programs/shutdown_spec.lua new file mode 100644 index 000000000..4cfa37ba1 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/shutdown_spec.lua @@ -0,0 +1,15 @@ +local capture = require "test_helpers".capture_program + +describe("The shutdown program", function() + + it("run the program", function() + local sleep = stub(_G, "sleep") + local shutdown = stub(os, "shutdown") + + expect(capture(stub, "shutdown")) + :matches { ok = true, output = "Goodbye\n", error = "" } + + expect(sleep):called_with(1) + expect(shutdown):called() + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/time_spec.lua b/src/test/resources/test-rom/spec/programs/time_spec.lua new file mode 100644 index 000000000..91f82fef0 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/time_spec.lua @@ -0,0 +1,12 @@ +local capture = require "test_helpers".capture_program + +describe("The time program", function() + + it("displays time", function() + local time = textutils.formatTime(os.time()) + local day = os.day() + + expect(capture(stub, "time")) + :matches { ok = true, output = "The time is " .. time .. " on Day " .. day .. "\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua new file mode 100644 index 000000000..93e4c1bb9 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua @@ -0,0 +1,89 @@ +local capture = require "test_helpers".capture_program + +describe("The craft program", function() + it("errors when not a turtle", function() + stub(_G, "turtle", nil) + + expect(capture(stub, "/rom/programs/turtle/craft.lua")) + :matches { ok = true, output = "", error = "Requires a Turtle\n" } + end) + + it("fails when turtle.craft() is unavailable", function() + stub(_G, "turtle", {}) + + expect(capture(stub, "/rom/programs/turtle/craft.lua")) + :matches { ok = true, output = "Requires a Crafty Turtle\n", error = "" } + end) + + it("displays its usage when given no arguments", function() + stub(_G, "turtle", { craft = function() end }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua")) + :matches { ok = true, output = "Usage: /rom/programs/turtle/craft.lua all|\n", error = "" } + end) + + it("displays its usage when given incorrect arguments", function() + stub(_G, "turtle", { craft = function() end }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua a")) + :matches { ok = true, output = "Usage: /rom/programs/turtle/craft.lua all|\n", error = "" } + end) + + it("crafts multiple items", function() + local item_count = 3 + stub(_G, "turtle", { + craft = function() + item_count = 1 + return true + end, + getItemCount = function() return item_count end, + getSelectedSlot = function() return 1 end, + }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua 2")) + :matches { ok = true, output = "2 items crafted\n", error = "" } + end) + + it("craft a single item", function() + local item_count = 2 + stub(_G, "turtle", { + craft = function() + item_count = 1 + return true + end, + getItemCount = function() return item_count end, + getSelectedSlot = function() return 1 end, + }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua 1")) + :matches { ok = true, output = "1 item crafted\n", error = "" } + end) + + it("crafts no items", function() + local item_count = 2 + stub(_G, "turtle", { + craft = function() + item_count = 1 + return false + end, + getItemCount = function() return item_count end, + getSelectedSlot = function() return 1 end, + }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua 1")) + :matches { ok = true, output = "No items crafted\n", error = "" } + end) + + it("crafts all items", function() + stub(_G, "turtle", { + craft = function() + return true + end, + getItemCount = function() return 17 end, + getSelectedSlot = function() return 1 end, + }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua all")) + :matches { ok = true, output = "17 items crafted\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua new file mode 100644 index 000000000..92f75b73c --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua @@ -0,0 +1,89 @@ +local capture = require "test_helpers".capture_program + +describe("The turtle equip program", function() + it("errors when not a turtle", function() + stub(_G, "turtle", nil) + + expect(capture(stub, "/rom/programs/turtle/equip.lua")) + :matches { ok = true, output = "", error = "Requires a Turtle\n" } + end) + + + it("displays its usage when given no arguments", function() + stub(_G, "turtle", {}) + + expect(capture(stub, "/rom/programs/turtle/equip.lua")) + :matches { ok = true, output = "Usage: /rom/programs/turtle/equip.lua \n", error = "" } + end) + + it("equip nothing", function() + stub(_G, "turtle", { + select = function() end, + getItemCount = function() return 0 end, + }) + + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left")) + :matches { ok = true, output = "Nothing to equip\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right")) + :matches { ok = true, output = "Nothing to equip\n", error = "" } + end) + + it("swaps existing upgrades", function() + stub(_G, "turtle", { + select = function() end, + getItemCount = function() return 1 end, + equipLeft = function() return true end, + equipRight = function() return true end, + }) + + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left")) + :matches { ok = true, output = "Items swapped\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right")) + :matches { ok = true, output = "Items swapped\n", error = "" } + end) + + describe("equips a new upgrade", function() + local function setup() + local item_count = 1 + stub(_G, "turtle", { + select = function() end, + getItemCount = function() return item_count end, + equipLeft = function() + item_count = 0 + return true + end, + equipRight = function() + item_count = 0 + return true + end, + }) + end + + it("on the left", function() + setup() + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left")) + :matches { ok = true, output = "Item equipped\n", error = "" } + end) + + it("on the right", function() + setup() + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right")) + :matches { ok = true, output = "Item equipped\n", error = "" } + end) + end) + + it("handles when an upgrade cannot be equipped", function() + stub(_G, "turtle", { + select = function() end, + getItemCount = function() return 1 end, + equipLeft = function() return false end, + equipRight = function() return false end, + }) + + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left")) + :matches { ok = true, output = "Item not equippable\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right")) + :matches { ok = true, output = "Item not equippable\n", error = "" } + end) + +end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua new file mode 100644 index 000000000..485a66111 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua @@ -0,0 +1,62 @@ +local capture = require "test_helpers".capture_program + +describe("The refuel program", function() + local function setup_turtle(fuel_level, fuel_limit, item_count) + stub(_G, "turtle", { + getFuelLevel = function() + return fuel_level + end, + getItemCount = function() + return item_count + end, + refuel = function(nLimit) + item_count = item_count - nLimit + fuel_level = fuel_level + nLimit + end, + select = function() + end, + getFuelLimit = function() + return fuel_limit + end, + }) + end + + it("errors when not a turtle", function() + stub(_G, "turtle", nil) + + expect(capture(stub, "/rom/programs/turtle/refuel.lua")) + :matches { ok = true, output = "", error = "Requires a Turtle\n" } + end) + + + it("displays its usage when given too many argument", function() + setup_turtle(0, 5, 0) + expect(capture(stub, "/rom/programs/turtle/refuel.lua a b")) + :matches { ok = true, output = "Usage: /rom/programs/turtle/refuel.lua [number]\n", error = "" } + end) + + it("requires a numeric argument", function() + setup_turtle(0, 0, 0) + expect(capture(stub, "/rom/programs/turtle/refuel.lua nothing")) + :matches { ok = true, output = "Invalid limit, expected a number or \"all\"\n", error = "" } + end) + + it("refuels the turtle", function() + setup_turtle(0, 10, 5) + + expect(capture(stub, "/rom/programs/turtle/refuel.lua 5")) + :matches { ok = true, output = "Fuel level is 5\n", error = "" } + end) + + it("reports when the fuel limit is reached", function() + setup_turtle(0, 5, 5) + expect(capture(stub, "/rom/programs/turtle/refuel.lua 5")) + :matches { ok = true, output = "Fuel level is 5\nFuel limit reached\n", error = "" } + end) + + it("reports when the fuel level is unlimited", function() + setup_turtle("unlimited", 5, 5) + expect(capture(stub, "/rom/programs/turtle/refuel.lua 5")) + :matches { ok = true, output = "Fuel level is unlimited\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua new file mode 100644 index 000000000..1d81334f6 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua @@ -0,0 +1,69 @@ +local capture = require "test_helpers".capture_program + +describe("The turtle unequip program", function() + it("errors when not a turtle", function() + stub(_G, "turtle", nil) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua")) + :matches { ok = true, output = "", error = "Requires a Turtle\n" } + end) + + + it("displays its usage when given no arguments", function() + stub(_G, "turtle", {}) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua")) + :matches { ok = true, output = "Usage: /rom/programs/turtle/unequip.lua \n", error = "" } + end) + + it("says when nothing was unequipped", function() + stub(_G, "turtle", { + select = function() end, + getItemCount = function() return 0 end, + equipRight = function() return true end, + equipLeft = function() return true end, + }) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua left")) + :matches { ok = true, output = "Nothing to unequip\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/unequip.lua right")) + :matches { ok = true, output = "Nothing to unequip\n", error = "" } + end) + + it("unequips a upgrade", function() + local item_count = 0 + stub(_G, "turtle", { + select = function() end, + getItemCount = function() return item_count end, + equipRight = function() + item_count = 1 + return true + end, + equipLeft = function() + item_count = 1 + return true + end, + }) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua left")) + :matches { ok = true, output = "Item unequipped\n", error = "" } + item_count = 0 + expect(capture(stub, "/rom/programs/turtle/unequip.lua right")) + :matches { ok = true, output = "Item unequipped\n", error = "" } + end) + + it("fails when the turtle is full", function() + stub(_G, "turtle", { + select = function() end, + getItemCount = function() return 1 end, + equipRight = function() return true end, + equipLeft = function() return true end, + }) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua left")) + :matches { ok = true, output = "No space to unequip item\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/unequip.lua right")) + :matches { ok = true, output = "No space to unequip item\n", error = "" } + end) + +end) diff --git a/src/test/resources/test-rom/spec/programs/type_spec.lua b/src/test/resources/test-rom/spec/programs/type_spec.lua new file mode 100644 index 000000000..09d59ee4a --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/type_spec.lua @@ -0,0 +1,25 @@ +local capture = require "test_helpers".capture_program + +describe("The type program", function() + + it("displays the usage with no arguments", function() + expect(capture(stub, "type")) + :matches { ok = true, output = "Usage: type \n", error = "" } + end) + + it("displays the output for a file", function() + expect(capture(stub, "type /rom/startup.lua")) + :matches { ok = true, output = "file\n", error = "" } + end) + + it("displays the output for a directory", function() + expect(capture(stub, "type /rom")) + :matches { ok = true, output = "directory\n", error = "" } + end) + + it("displays the output for a not existing path", function() + expect(capture(stub, "type /rom/nothing")) + :matches { ok = true, output = "No such path\n", error = "" } + end) + +end) diff --git a/src/test/resources/test-rom/spec/support/debug_ext.lua b/src/test/resources/test-rom/spec/support/debug_ext.lua new file mode 100644 index 000000000..10b9b89c3 --- /dev/null +++ b/src/test/resources/test-rom/spec/support/debug_ext.lua @@ -0,0 +1,9 @@ +local function getupvalue(fn, name) + for i = 1, debug.getinfo(fn, "u").nups do + local up_name, value = debug.getupvalue(fn, i) + if up_name == name then return value end + end + error("Cannot find upvalue with name " .. name, 2) +end + +return { getupvalue = getupvalue } diff --git a/src/test/resources/test-rom/spec/support/fake_computer.lua b/src/test/resources/test-rom/spec/support/fake_computer.lua new file mode 100644 index 000000000..09f2c6223 --- /dev/null +++ b/src/test/resources/test-rom/spec/support/fake_computer.lua @@ -0,0 +1,180 @@ +local function keys(tbl) + local keys = {} + for k in pairs(tbl) do keys[#keys + 1] = k end + return keys +end + +local safe_globals = { + "assert", "bit32", "coroutine", "debug", "error", "fs", "getmetatable", "io", "ipairs", "math", "next", "pairs", + "pcall", "print", "printError", "rawequal", "rawget", "rawlen", "rawset", "select", "setmetatable", "string", + "table", "term", "textutils", "tonumber", "tostring", "type", "utf8", "xpcall", +} + +--- Create a fake computer. +local function make_computer(id, fn) + local env = setmetatable({}, _G) + + local peripherals = {} + local pending_timers, next_timer, clock = {}, 0, 0 + local events = { { n = 1, env } } + local function queue_event(...) events[#events + 1] = table.pack(...) end + + for _, k in pairs(safe_globals) do env[k] = _G[k] end + env.peripheral = { + getNames = function() return keys(peripherals) end, + isPresent = function(name) return peripherals[name] ~= nil end, + getType = function(name) return peripherals[name] and getmetatable(peripherals[name]).type end, + getMethods = function(name) return peripherals[name] and keys(peripherals[name]) end, + call = function(name, method, ...) + local p = peripherals[name] + if p then return p[method](...) end + return nil + end, + wrap = function(name) return peripherals[name] end, + } + env.os = { + getComputerID = function() return id end, + queueEvent = queue_event, + pullEventRaw = coroutine.yield, + pullEvent = function(filter) + local event_data = table.pack(coroutine.yield(filter)) + if event_data[1] == "terminate" then error("Terminated", 0) end + return table.unpack(event_data, 1, event_data.n) + end, + startTimer = function(delay) + local t = next_timer + pending_timers[t], next_timer = clock + delay, next_timer + 1 + return t + end, + clock = function() return clock end, + sleep = function(time) + local timer = env.os.startTimer(time or 0) + repeat local _, id = env.os.pullEvent("timer") until id == timer + end, + } + env.sleep = env.os.sleep + env.dofile = function(path) + local fn, err = loadfile(path, nil, env) + if fn then return fn() else error(err, 2) end + end + + local co = coroutine.create(fn) + local filter = nil + local function step() + while true do + if #events == 0 or coroutine.status(co) == "dead" then return false end + + local ev = table.remove(events, 1) + if filter == nil or ev[1] == filter or ev[1] == "terminated" then + local ok, result = coroutine.resume(co, table.unpack(ev, 1, ev.n)) + if not ok then + if type(result) == "table" and result.trace == nil then result.trace = debug.traceback(co) end + error(result, 0) + end + filter = result + return true + end + end + end + + local function advance(dt) + clock = clock + dt + for id, clk in pairs(pending_timers) do + if clk <= clock then + queue_event("timer", id) + pending_timers[id] = nil + end + end + end + + return { env = env, peripherals = peripherals, queue_event = queue_event, step = step, co = co, advance = advance } +end + +local function parse_channel(c) + if c < 0 or c > 65535 then error("Expected number in range 0-65535", 3) end + return c +end + +--- Add a modem to a computer on a particular side +local function add_modem(owner, side) + local open, adjacent = {}, {} + local peripheral = setmetatable({ + open = function(channel) open[parse_channel(channel)] = true end, + close = function(channel) open[parse_channel(channel)] = false end, + closeAll = function(channel) open = {} end, + isOpen = function(channel) return open[parse_channel(channel)] == true end, + transmit = function(channel, reply_channel, payload) + channel, reply_channel = parse_channel(channel), parse_channel(reply_channel) + + for _, adjacent in pairs(adjacent) do + if adjacent.open[channel] then + adjacent.owner.queue_event("modem_message", adjacent.side, channel, reply_channel, payload, 123) + end + end + end, + }, { type = "modem" }) + owner.peripherals[side] = peripheral + return { adjacent = adjacent, side = side, owner = owner, open = open } +end + +local function add_modem_edge(modem1, modem2) + table.insert(modem1.adjacent, modem2) + table.insert(modem2.adjacent, modem1) +end + +--- Load an API into the computer's environment. +local function add_api(computer, path) + local name = fs.getName(path) + if name:sub(-4) == ".lua" then name = name:sub(1, -5) end + + local child_env = {} + setmetatable(child_env, { __index = computer.env }) + assert(loadfile(path, nil, child_env))() + + local api = {} + for k, v in pairs(child_env) do api[k] = v end + + computer.env[name] = api +end + +--- Step all computers forward by one event. +local function step_all(computers) + local any = false + for _, computer in pairs(computers) do + if computer.step() then any = true end + end + return any +end + +--- Run all computers until their event queue is empty. +local function run_all(computers, require_done) + while step_all(computers) do end + + if require_done ~= false then + if type(require_done) == "table" then + for _, v in ipairs(require_done) do require_done[v] = true end + end + + for _, computer in pairs(computers) do + if coroutine.status(computer.co) ~= "dead" and (type(require_done) ~= "table" or require_done[computer]) then + error(debug.traceback(computer.co, ("Computer #%d did not shutdown"):format(computer.env.os.getComputerID())), 0) + end + end + end +end + +--- Advance all computers by a given time. +local function advance_all(computers, dt) + for _, computer in pairs(computers) do computer.advance(dt) end +end + +return { + make_computer = make_computer, + add_modem = add_modem, + add_modem_edge = add_modem_edge, + add_api = add_api, + + step_all = step_all, + run_all = run_all, + advance_all = advance_all, +} diff --git a/src/test/resources/test-rom/spec/test_helpers.lua b/src/test/resources/test-rom/spec/test_helpers.lua new file mode 100644 index 000000000..5d1ba9f1c --- /dev/null +++ b/src/test/resources/test-rom/spec/test_helpers.lua @@ -0,0 +1,62 @@ +--- Run a program and capture its output +-- +-- @tparam function(tbl:table, var:string, value:string) stub The active stub function. +-- @tparam string program The program name. +-- @tparam string ... Arguments to this program. +-- @treturn { ok = boolean, output = string, error = string, combined = string } +-- Whether this program terminated successfully, and the various output streams. +local function capture_program(stub, program, ...) + local output, error, combined = {}, {}, {} + + local function out(stream, msg) + table.insert(stream, msg) + table.insert(combined, msg) + end + + stub(_G, "print", function(...) + for i = 1, select('#', ...) do + if i > 1 then out(output, " ") end + out(output, tostring(select(i, ...))) + end + out(output, "\n") + end) + + stub(_G, "printError", function(...) + for i = 1, select('#', ...) do + if i > 1 then out(error, " ") end + out(error, tostring(select(i, ...))) + end + out(error, "\n") + end) + + stub(_G, "write", function(msg) out(output, tostring(msg)) end) + + local ok = shell.run(program, ...) + + return { + output = table.concat(output), + error = table.concat(error), + combined = table.concat(combined), + ok = ok, + } +end + +--- Run a function redirecting to a new window with the given dimensions +-- +-- @tparam number width The window's width +-- @tparam number height The window's height +-- @tparam function() fn The action to run +-- @treturn window.Window The window, whose content can be queried. +local function with_window(width, height, fn) + local current = term.current() + local redirect = window.create(current, 1, 1, width, height, false) + term.redirect(redirect) + fn() + term.redirect(current) + return redirect +end + +return { + capture_program = capture_program, + with_window = with_window, +}