diff --git a/.editorconfig b/.editorconfig index f11468850..d57b269a4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,5 +14,9 @@ trim_trailing_whitespace = false [*.sexp] indent_size = 2 +[*.yml] +indent_size = 2 + + [*.properties] insert_final_newline = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..e05a3a6dd --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Ignore changes in generated files +src/generated/resources/data/** linguist-generated diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index d0caedbf2..3ae99ee1e 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -8,15 +8,23 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 + - name: Cache gradle dependencies + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('gradle.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Build with Gradle - run: ./gradlew build --no-daemon + run: ./gradlew build --no-daemon || ./gradlew build --no-daemon - name: Upload Jar uses: actions/upload-artifact@v1 @@ -34,6 +42,9 @@ jobs: - name: Lint Lua code run: | test -d bin || mkdir bin - test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/bin/illuaminate + test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate chmod +x bin/illuaminate bin/illuaminate lint + + - name: Check whitespace + run: python3 tools/check-lines.py diff --git a/.github/workflows/make-doc.sh b/.github/workflows/make-doc.sh new file mode 100755 index 000000000..e447c3046 --- /dev/null +++ b/.github/workflows/make-doc.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -eu + +DEST="${GITHUB_REF#refs/*/}" +echo "Uploading docs to https://tweaked.cc/$DEST" + +# Setup ssh key +mkdir -p "$HOME/.ssh/" +echo "$SSH_KEY" > "$HOME/.ssh/key" +chmod 600 "$HOME/.ssh/key" + +# And upload +rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \ + "$GITHUB_WORKSPACE/doc/" \ + "$SSH_USER@$SSH_HOST:/var/www/tweaked.cc/$DEST" diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml new file mode 100644 index 000000000..1d5e4605d --- /dev/null +++ b/.github/workflows/make-doc.yml @@ -0,0 +1,29 @@ +name: Build documentation + +on: + push: + branches: [ master ] + tags: + +jobs: + make_doc: + name: Build + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Build documentation + run: | + test -d bin || mkdir bin + test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate + chmod +x bin/illuaminate + bin/illuaminate doc-gen + + - name: Upload documentation + run: .github/workflows/make-doc.sh 2> /dev/null + env: + SSH_KEY: ${{ secrets.SSH_KEY }} + SSH_USER: ${{ secrets.SSH_USER }} + SSH_HOST: ${{ secrets.SSH_HOST }} + SSH_PORT: ${{ secrets.SSH_PORT }} diff --git a/.gitignore b/.gitignore index 80c50f9b8..42f6759db 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ /logs /build /out +/doc/**/*.html +/doc/index.json # Runtime directories /run @@ -21,3 +23,5 @@ .settings/ bin/ *.launch + +/src/generated/resources/.cache diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..2475ac724 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing to CC: Tweaked +As with many open source projects, CC: Tweaked thrives on contributions from other people! This document (hopefully) +provides an introduction as to how to get started in helping out. + +If you've any other questions, [just ask the community][community] or [open an issue][new-issue]. + +## Reporting issues +If you have a bug, suggestion, or other feedback, the best thing to do is [file an issue][new-issue]. When doing so, +do use the issue templates - they provide a useful hint on what information to provide. + +## Developing +In order to develop CC: Tweaked, you'll need to download the source code and then run it. This is a pretty simple +process. + + - **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked` + - **Setup Forge:** `./gradlew build` + - **Run Minecraft:** `./gradlew runClient` (or run the `GradleStart` class from your IDE). + +If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`. +These commands may take a few minutes to run the first time, as the environment is set up, but should be much faster +afterwards. + +### Code linters +CC: Tweaked uses a couple of "linters" on its source code, to enforce a consistent style across the project. While these +are run whenever you submit a PR, it's often useful to run this before committing. + + - **[Checkstyle]:** Checks Java code to ensure it is consistently formatted. This can be run with `./gradlew build` or + `./gradle check`. + - **[illuaminate]:** Checks Lua code for semantic and styleistic issues. See [the usage section][illuaminate-usage] for + how to download and run it. + +[new-issue]: https://github.com/SquidDev-CC/CC-Tweaked/issues/new/choose "Create a new issue" +[community]: README.md#Community "Get in touch with the community." +[checkstyle]: https://checkstyle.org/ +[illuaminate]: https://github.com/SquidDev/illuaminate/ +[illuaminate-usage]: https://github.com/SquidDev/illuaminate/blob/master/README.md#usage diff --git a/README.md b/README.md index d75213c02..3488c58b0 100644 --- a/README.md +++ b/README.md @@ -37,20 +37,14 @@ ## Relation to CCTweaks? computers. ## Contributing -Any contribution is welcome, be that using the mod, reporting bugs or contributing code. In order to start helping -develop CC:T, you'll need to follow these steps: - - - **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked` - - **Setup Forge:** `./gradlew build` - - **Test your changes:** `./gradlew runClient` (or run the `GradleStart` class from your IDE). - -If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`. +Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started +developing the mod, [check out the instructions here](CONTRIBUTING.md#developing). ## Community If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about -ComputerCraft we have a [forum](https://forums.computercraft.cc/) and [Discord guild](https://discord.gg/H2UyJXe)! -There's also a fairly populated, albeit quiet [IRC channel](http://webchat.esper.net/?channels=#computercraft), if -that's more your cup of tea. +ComputerCraft we have a [forum](https://forums.computercraft.cc/) and [Discord guild](https://discord.computercraft.cc)! +There's also a fairly populated, albeit quiet [IRC channel](http://webchat.esper.net/?channels=computercraft), if that's +more your cup of tea. I'd generally recommend you don't contact me directly (email, DM, etc...) unless absolutely necessary (i.e. in order to report exploits). You'll get a far quicker response if you ask the whole community! @@ -66,7 +60,7 @@ ## Using } dependencies { - implementation "org.squiddev:cc-tweaked-${mc_version}:${cct_version}" + implementation fg.deobf("org.squiddev:cc-tweaked-${mc_version}:${cct_version}") } ``` diff --git a/build.gradle b/build.gradle index 3c0b386da..8fc56233d 100644 --- a/build.gradle +++ b/build.gradle @@ -57,6 +57,19 @@ } } } + + data { + workingDirectory project.file('run') + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + property 'forge.logging.console.level', 'debug' + + args '--mod', 'computercraft', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + mods { + computercraft { + source sourceSets.main + } + } + } } mappings channel: 'snapshot', version: "${mappings_version}".toString() @@ -64,19 +77,15 @@ accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') } +sourceSets.main.resources { + srcDir 'src/generated/resources' +} + repositories { - maven { - name "JEI" - url "https://dvs1.progwml6.com/files/maven" - } maven { name "SquidDev" url "https://squiddev.cc/maven" } - maven { - name "CraftTweaker" - url "https://maven.blamejared.com/" - } } configurations { @@ -93,7 +102,7 @@ accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') compileOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.2:api") runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.2") - shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' + shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2' diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 000000000..c22acd230 --- /dev/null +++ b/doc/index.md @@ -0,0 +1,11 @@ +# ![CC: Tweaked](logo.png) [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") + +CC: Tweaked is a fork of [ComputerCraft], adding programmable computers, turtles and more to Minecraft. + +This website contains documentation for all Lua libraries and APIs from the latest version of CC: Tweaked. This +documentation is still in development, so will most likely be incomplete. If you've found something you think is wrong, +or would like to help out [please get in touch on GitHub][gh]. + +[bug]: https://github.com/SquidDev-CC/CC-Tweaked/issues/new/choose +[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub" +[gh]: https://github.com/SquidDev-CC/CC-Tweaked "CC:Tweaked on GitHub" diff --git a/logo.png b/doc/logo.png similarity index 100% rename from logo.png rename to doc/logo.png diff --git a/doc/stub/commands.lua b/doc/stub/commands.lua new file mode 100644 index 000000000..89b0f604b --- /dev/null +++ b/doc/stub/commands.lua @@ -0,0 +1,6 @@ +function exec(command) end +function execAsync(commad) end +function list() end +function getBlockPosition() end +function getBlockInfos(min_x, min_y, min_z, max_x, max_y, max_z) end +function getBlockInfo(x, y, z) end diff --git a/doc/stub/fs.lua b/doc/stub/fs.lua new file mode 100644 index 000000000..73d578e01 --- /dev/null +++ b/doc/stub/fs.lua @@ -0,0 +1,42 @@ +--- The FS API allows you to manipulate files and the filesystem. +-- +-- @module fs + +function list(path) end +function combine(base, child) end +function getName(path) end +function getSize(path) end +function exists(path) end +function isDir(path) end +function isReadOnly(path) end +function makeDir(path) end +function move(from, to) end +function copy(from, to) end +function delete(path) end +function open(path, mode) end +function getDrive(path) end +function getFreeSpace(path) end +function find(pattern) end +function getDir(path) end + +--- A file handle which can be read from. +-- +-- @type ReadHandle +-- @see fs.open +local ReadHandle = {} +function ReadHandle.read(count) end +function ReadHandle.readAll() end +function ReadHandle.readLine(with_trailing) end +function ReadHandle.seek(whence, offset) end +function ReadHandle.close() end + +--- A file handle which can be written to. +-- +-- @type WriteHandle +-- @see fs.open +local WriteHandle = {} +function WriteHandle.write(text) end +function WriteHandle.writeLine(text) end +function WriteHandle.flush(text) end +function WriteHandle.seek(whence, offset) end +function WriteHandle.close() end diff --git a/doc/stub/http.lua b/doc/stub/http.lua new file mode 100644 index 000000000..8e8a24c08 --- /dev/null +++ b/doc/stub/http.lua @@ -0,0 +1,229 @@ +--- The http library allows communicating with web servers, sending and +-- receiving data from them. +-- +-- #### `http_check` event +-- +-- @module http + +--- Asynchronously make a HTTP request to the given url. +-- +-- This returns immediately, a [`http_success`](#http-success-event) or +-- [`http_failure`](#http-failure-event) will be queued once the request has +-- completed. +-- +-- @tparam string url The url to request +-- @tparam[opt] string body An optional string containing the body of the +-- request. If specified, a `POST` request will be made instead. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, body? = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. +-- +-- This table form is an expanded version of the previous syntax. All arguments +-- from above are passed in as fields instead (for instance, +-- `http.request("https://example.com")` becomes `http.request { url = +-- "https://example.com" }`). +-- +-- This table also accepts several additional options: +-- +-- - `method`: Which HTTP method to use, for instance `"PATCH"` or `"DELETE"`. +-- - `redirect`: Whether to follow HTTP redirects. Defaults to true. +-- +-- @see http.get For a synchronous way to make GET requests. +-- @see http.post For a synchronous way to make POST requests. +function request(...) end + +--- Make a HTTP GET request to the given url. +-- +-- @tparam string url The url to request +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. See @{http.request} for details on how +-- these options behave. +-- +-- @treturn Response The resulting http response, which can be read from. +-- @treturn[2] nil When the http request failed, such as in the event of a 404 +-- error or connection timeout. +-- @treturn string A message detailing why the request failed. +-- @treturn Response|nil The failing http response, if available. +-- +-- @usage Make a request to [example.computercraft.cc](https://example.computercraft.cc), +-- and print the returned page. +-- ```lua +-- local request = http.get("https://example.computercraft.cc") +-- print(request.readAll()) +-- -- => HTTP is working! +-- request.close() +-- ``` +function get(...) end + +--- Make a HTTP POST request to the given url. +-- +-- @tparam string url The url to request +-- @tparam string body The body of the POST request. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, body? = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. See @{http.request} for details on how +-- these options behave. +-- +-- @treturn Response The resulting http response, which can be read from. +-- @treturn[2] nil When the http request failed, such as in the event of a 404 +-- error or connection timeout. +-- @treturn string A message detailing why the request failed. +-- @treturn Response|nil The failing http response, if available. +function post(...) end + +--- A http response. This acts very much like a @{fs.ReadHandle|file}, though +-- provides some http specific methods. +-- +-- #### `http_success` event +-- #### `http_failure` event +-- +-- @type Response +-- @see http.request On how to make a http request. +local Response = {} + +--- Returns the response code and response message returned by the server +-- +-- @treturn number The response code (i.e. 200) +-- @treturn string The response message (i.e. "OK") +function Response.getResponseCode() end + +--- Get a table containing the response's headers, in a format similar to that +-- required by @{http.request}. If multiple headers are sent with the same +-- name, they will be combined with a comma. +-- +-- @treturn { [string]=string } The response's headers. +-- Make a request to [example.computercraft.cc](https://example.computercraft.cc), +-- and print the returned headers. +-- ```lua +-- local request = http.get("https://example.computercraft.cc") +-- print(textutils.serialize(request.getResponseHeaders())) +-- -- => { +-- -- [ "Content-Type" ] = "text/plain; charset=utf8", +-- -- [ "content-length" ] = 17, +-- -- ... +-- -- } +-- request.close() +-- ``` +function Response.getResponseHeaders() end + +function Response.read(count) end +function Response.readAll() end +function Response.readLine(with_trailing) end +function Response.seek(whence, offset) end +function Response.close() end + +--- Asynchronously determine whether a URL can be requested. +-- +-- If this returns `true`, one should also listen for [`http_check` +-- events](#http-check-event) which will container further information about +-- whether the URL is allowed or not. +-- +-- @tparam string url The URL to check. +-- @treturn true When this url is not invalid. This does not imply that it is +-- allowed - see the comment above. +-- @treturn[2] false When this url is invalid. +-- @treturn string A reason why this URL is not valid (for instance, if it is +-- malformed, or blocked). +-- +-- @see http.checkURL For a synchronous version. +function checkURLAsync(url) end + +--- Determine whether a URL can be requested. +-- +-- If this returns `true`, one should also listen for [`http_check` +-- events](#http-check-event) which will container further information about +-- whether the URL is allowed or not. +-- +-- @tparam string url The URL to check. +-- @treturn true When this url is valid and can be requested via @{http.request}. +-- @treturn[2] false When this url is invalid. +-- @treturn string A reason why this URL is not valid (for instance, if it is +-- malformed, or blocked). +-- +-- @see http.checkURLAsync For an asynchronous version. +-- +-- @usage +-- ```lua +-- print(http.checkURL("https://example.computercraft.cc/")) +-- -- => true +-- print(http.checkURL("http://localhost/")) +-- -- => false Domain not permitted +-- print(http.checkURL("not a url")) +-- -- => false URL malformed +-- ``` +function checkURL(url) end + +--- Open a websocket. +-- +-- @tparam string url The websocket url to connect to. This should have the +-- `ws://` or `wss://` protocol. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of the initial websocket connection. +-- +-- @treturn Websocket The websocket connection. +-- @treturn[2] false If the websocket connection failed. +-- @treturn string An error message describing why the connection failed. +function websocket(url, headers) end + +--- Asynchronously open a websocket. +-- +-- This returns immediately, a [`websocket_success`](#websocket-success-event) +-- or [`websocket_failure`](#websocket-failure-event) will be queued once the +-- request has completed. +-- +-- @tparam string url The websocket url to connect to. This should have the +-- `ws://` or `wss://` protocol. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of the initial websocket connection. +function websocketAsync(url, headers) end + +--- A websocket, which can be used to send an receive messages with a web +-- server. +-- +-- @type Websocket +-- @see http.websocket On how to open a websocket. +local Websocket = {} + +--- Send a websocket message to the connected server. +-- +-- @tparam string message The message to send. +-- @tparam[opt] boolean binary Whether this message should be treated as a +-- binary string, rather than encoded text. +-- @throws If the websocket has been closed. +function Websocket.send(message, binary) end + +--- Wait for a message from the server. +-- +-- @tparam[opt] number timeout The number of seconds to wait if no message is +-- received. +-- @treturn[1] string The received message. +-- @treturn boolean If this was a binary message. +-- @treturn[2] nil If the websocket was closed while waiting, or if we timed out. +-- @throws If the websocket has been closed. +function Websocket.receive(timeout) end + +--- Close this websocket. This will terminate the connection, meaning messages +-- can no longer be sent or received along it. +function Websocket.close() end diff --git a/doc/stub/os.lua b/doc/stub/os.lua new file mode 100644 index 000000000..163d2c2b0 --- /dev/null +++ b/doc/stub/os.lua @@ -0,0 +1,17 @@ +function queueEvent(event, ...) end +function startTimer(delay) end +function setAlarm(time) end +function shutdown() end +function reboot() end +function getComputerID() end +computerID = getComputerID +function setComputerLabel(label) end +function getComputerLabel() end +computerLabel = getComputerLabel +function clock() end +function time(timezone) end +function day(timezone) end +function cancelTimer(id) end +function cancelAlarm(id) end +function epoch(timezone) end +function date(format, time) end diff --git a/doc/stub/redstone.lua b/doc/stub/redstone.lua new file mode 100644 index 000000000..cf10a45ca --- /dev/null +++ b/doc/stub/redstone.lua @@ -0,0 +1,14 @@ +function getSides() end +function setOutput(side, on) end +function getOutput(side) end +function getInput(side) end +function setBundledOutput(side, output) end +function getBundledOutput(side) end +function getBundledInput(side) end +function testBundledInput(side, mask) end +function setAnalogOutput(side, value) end +setAnalogueOutput = setAnalogOutput +function getAnalogOutput(sid) end +getAnalogueOutput = getAnalogOutput +function getAnalogInput(side) end +getAnalogueInput = getAnaloguInput diff --git a/doc/stub/term.lua b/doc/stub/term.lua new file mode 100644 index 000000000..2111949b6 --- /dev/null +++ b/doc/stub/term.lua @@ -0,0 +1,52 @@ +function write(text) end +function scroll(lines) end +function setCursorPos(x, y) end +function setCursorBlink(blink) end +function getCursorPos() end +function getSize() end +function clear() end +function clearLine() end +function setTextColour(colour) end +setTextColor = setTextColour +function setBackgroundColour(colour) end +setBackgroundColor = setBackgroundColour +function isColour() end +isColor = isColour +function getTextColour() end +getTextColor = getTextColor +function getBackgroundColour() end +getBackgroundColour = getBackgroundColour +function blit(text, text_colours, background_colours) end +function setPaletteColour(colour, ...) end +setPaletteColour = setPaletteColour +function getPaletteColour(colour, ...) end +getPaletteColour = getPaletteColour +function nativePaletteColour(colour) end +nativePaletteColour = nativePaletteColour + +--- @type Redirect +local Redirect = {} + +Redirect.write = write +Redirect.scroll = scroll +Redirect.setCursorPos = setCursorPos +Redirect.setCursorBlink = setCursorBlink +Redirect.getCursorPos = getCursorPos +Redirect.getSize = getSize +Redirect.clear = clear +Redirect.clearLine = clearLine +Redirect.setTextColour = setTextColour +Redirect.setTextColor = setTextColor +Redirect.setBackgroundColour = setBackgroundColour +Redirect.setBackgroundColor = setBackgroundColor +Redirect.isColour = isColour +Redirect.isColor = isColor +Redirect.getTextColour = getTextColour +Redirect.getTextColor = getTextColor +Redirect.getBackgroundColour = getBackgroundColour +Redirect.getBackgroundColor = getBackgroundColor +Redirect.blit = blit +Redirect.setPaletteColour = setPaletteColour +Redirect.setPaletteColor = setPaletteColor +Redirect.getPaletteColour = getPaletteColour +Redirect.getPaletteColor = getPaletteColor diff --git a/doc/stub/turtle.lua b/doc/stub/turtle.lua new file mode 100644 index 000000000..7fabd2a8a --- /dev/null +++ b/doc/stub/turtle.lua @@ -0,0 +1,230 @@ +--- Move the turtle forward one block. +-- @treturn boolean Whether the turtle could successfully move. +-- @treturn string|nil The reason the turtle could not move. +function forward() end + +--- Move the turtle backwards one block. +-- @treturn boolean Whether the turtle could successfully move. +-- @treturn string|nil The reason the turtle could not move. +function back() end + +--- Move the turtle up one block. +-- @treturn boolean Whether the turtle could successfully move. +-- @treturn string|nil The reason the turtle could not move. +function up() end + +--- Move the turtle down one block. +-- @treturn boolean Whether the turtle could successfully move. +-- @treturn string|nil The reason the turtle could not move. +function down() end + +--- Rotate the turtle 90 degress to the left. +function turnLeft() end + +--- Rotate the turtle 90 degress to the right. +function turnRight() end + +--- Attempt to break the block in front of the turtle. +-- +-- This requires a turtle tool capable of breaking the block. Diamond pickaxes +-- (mining turtles) can break any vanilla block, but other tools (such as axes) +-- are more limited. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether a block was broken. +-- @treturn string|nil The reason no block was broken. +function dig(side) end + +--- Attempt to break the block above the turtle. See @{dig} for full details. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether a block was broken. +-- @treturn string|nil The reason no block was broken. +function digUp(side) end + +--- Attempt to break the block below the turtle. See @{dig} for full details. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether a block was broken. +-- @treturn string|nil The reason no block was broken. +function digDown(side) end + +--- Attack the entity in front of the turtle. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether an entity was attacked. +-- @treturn string|nil The reason nothing was attacked. +function attack(side) end + +--- Attack the entity above the turtle. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether an entity was attacked. +-- @treturn string|nil The reason nothing was attacked. +function attackUp(side) end + +--- Attack the entity below the turtle. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether an entity was attacked. +-- @treturn string|nil The reason nothing was attacked. +function attackDown(side) end + +--- Place a block or item into the world in front of the turtle. +-- +-- @treturn boolean Whether the block could be placed. +-- @treturn string|nil The reason the block was not placed. +function place() end + +--- Place a block or item into the world above the turtle. +-- +-- @treturn boolean Whether the block could be placed. +-- @treturn string|nil The reason the block was not placed. +function placeUp() end + +--- Place a block or item into the world below the turtle. +-- +-- @treturn boolean Whether the block could be placed. +-- @treturn string|nil The reason the block was not placed. +function placeDown() end + +--- Drop the currently selected stack into the inventory in front of the turtle, +-- or as an item into the world if there is no inventory. +-- +-- @tparam[opt] number count The number of items to drop. If not given, the +-- entire stack will be dropped. +-- @treturn boolean Whether items were dropped. +-- @treturn string|nil The reason the no items were dropped. +-- @see select +function drop(count) end + +--- Drop the currently selected stack into the inventory above the turtle, or as +-- an item into the world if there is no inventory. +-- +-- @tparam[opt] number count The number of items to drop. If not given, the +-- entire stack will be dropped. +-- @treturn boolean Whether items were dropped. +-- @treturn string|nil The reason the no items were dropped. +-- @see select +function dropUp(count) end + +--- Drop the currently selected stack into the inventory below the turtle, or as +-- an item into the world if there is no inventory. +-- +-- @tparam[opt] number count The number of items to drop. If not given, the +-- entire stack will be dropped. +-- @treturn boolean Whether items were dropped. +-- @treturn string|nil The reason the no items were dropped. +-- @see select +function dropDown(count) end + +--- Suck an item from the inventory in front of the turtle, or from an item +-- floating in the world. +-- +-- This will pull items into the first acceptable slot, starting at the +-- @{select|currently selected} one. +-- +-- @tparam[opt] number count The number of items to suck. If not given, up to a +-- stack of items will be picked up. +-- @treturn boolean Whether items were picked up. +-- @treturn string|nil The reason the no items were picked up. +function suck(count) end + +--- Suck an item from the inventory above the turtle, or from an item floating +-- in the world. +-- +-- @tparam[opt] number count The number of items to suck. If not given, up to a +-- stack of items will be picked up. +-- @treturn boolean Whether items were picked up. +-- @treturn string|nil The reason the no items were picked up. +function suckUp(count) end + +--- Suck an item from the inventory below the turtle, or from an item floating +-- in the world. +-- +-- @tparam[opt] number count The number of items to suck. If not given, up to a +-- stack of items will be picked up. +-- @treturn boolean Whether items were picked up. +-- @treturn string|nil The reason the no items were picked up. +function suckDown(count) end + +--- Check if there is a solid block in front of the turtle. In this case, solid +-- refers to any non-air or liquid block. +-- +-- @treturn boolean If there is a solid block in front. +function detect() end + +--- Check if there is a solid block above the turtle. +-- +-- @treturn boolean If there is a solid block above. +function detectUp() end + +--- Check if there is a solid block below the turtle. +-- +-- @treturn boolean If there is a solid block below. +function detectDown() end + +function compare() end +function compareUp() end +function compareDown() end + +function inspect() end +function inspectUp() end +function inspectDown() end + + +--- Change the currently selected slot. +-- +-- The selected slot is determines what slot actions like @{drop} or +-- @{getItemCount} act on. +-- +-- @tparam number slot The slot to select. +-- @see getSelectedSlot +function select(slot) end + +--- Get the currently selected slot. +-- +-- @treturn number The current slot. +-- @see select +function getSelectedSlot() end + +--- Get the number of items in the given slot. +-- +-- @tparam[opt] number slot The slot we wish to check. Defaults to the @{turtle.select|selected slot}. +-- @treturn number The number of items in this slot. +function getItemCount(slot) end + +--- Get the remaining number of items which may be stored in this stack. +-- +-- For instance, if a slot contains 13 blocks of dirt, it has room for another 51. +-- +-- @tparam[opt] number slot The slot we wish to check. Defaults to the @{turtle.select|selected slot}. +-- @treturn number The space left in this slot. +function getItemSpace(slot) end + + +--- Get detailed information about the items in the given slot. +-- +-- @tparam[opt] number slot The slot to get information about. Defaults to the @{turtle.select|selected slot}. +-- @treturn nil|table Information about the given slot, or @{nil} if it is empty. +-- @usage Print the current slot, assuming it contains 13 dirt. +-- +-- print(textutils.serialize(turtle.getItemDetail())) +-- -- => { +-- -- name = "minecraft:dirt", +-- -- damage = 0, +-- -- count = 13, +-- -- } +function getItemDetail(slot) end + +function getFuelLevel() end + +function refuel(count) end +function compareTo(slot) end +function transferTo(slot, count) end + +function getFuelLimit() end +function equipLeft() end +function equipRight() end + +function craft(limit) end diff --git a/doc/styles.css b/doc/styles.css new file mode 100644 index 000000000..ef14a7d94 --- /dev/null +++ b/doc/styles.css @@ -0,0 +1,186 @@ +/* Basic reset on elements */ +h1, h2, h3, h4, p, table, div, body { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* Make the page a little more airy */ +body { + margin: 20px auto; + max-width: 1200px; + padding: 0 10px; + line-height: 1.6; + color: #222; + background: #fff; +} + +/* Try to use system default fonts. */ +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", + "Droid Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; +} + +code, pre, .parameter, .type, .definition-name, .reference { + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; +} + +/* Some definitions of basic tags */ +code { + color: #c7254e; + background-color: #f9f2f4; +} + +p { + margin: 0.9em 0; +} + +h1 { + font-size: 1.5em; + font-weight: lighter; + border-bottom: solid 1px #aaa; +} + +h2, h3, h4 { margin: 1.4em 0 0.3em;} +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; font-weight: bold; } +h4 { font-size: 1.06em; } + +a, a:visited, a:active { font-weight: bold; color: #004080; text-decoration: none; } +a:hover { text-decoration: underline; } + +blockquote { margin-left: 3em; } + +/* Stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* Make the target distinct; helps when we're navigating to a function */ +a:target + * { background-color: #FFFF99; } + +/* Allow linking to any subsection */ +a[name]::before { content: "#"; } + +/* Layout */ +#main { + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + min-height: calc(100vh - 100px); +} + +#main > nav { + flex-basis: 30%; + min-width: 150px; + max-width: 250px; + background-color: #f0f0f0; +} + +nav h1, nav ul { padding: 0em 10px; } + +nav h2 { + background-color:#e7e7e7; + font-size: 1.1em; + color:#000000; + padding: 5px 10px; +} + +nav ul { + list-style-type: none; + margin: 0; +} + +#content { + flex-shrink: 1; + flex-basis: 80%; + padding: 0px 10px; +} + +footer { + text-align: right; + font-size: 0.8em; +} + +/* The definition lists at the top of each page */ +table.definition-list { + border-collapse: collapse; + width: 100%; +} + +table.definition-list td, table.definition-list th { + border: 1px solid #cccccc; + padding: 5px; +} + +table.definition-list th { + background-color: #f0f0f0; + min-width: 200px; + white-space: nowrap; + text-align: right; +} + +table.definition-list td { width: 100%; } + +dl.definition dt { + border-top: 1px solid #ccc; + padding-top: 1em; + display: flex; +} + +dl.definition dt .definition-name { + padding: 0 0.1em; + margin: 0 0.1em; + flex-grow: 1; +} + + +dl.definition dd { + padding-bottom: 1em; + margin: 10px 0 0 20px; +} + +dl.definition h3 { + font-size: .95em; +} + +/* Links to source-code */ +.source-link { font-size: 0.8em; } +.source-link::before { content: '[' } +.source-link::after { content: ']' } +a.source-link, a.source-link:visited, a.source-link:active { color: #505050; } + +/* Method definitions */ +span.parameter:after { content:":"; padding-left: 0.3em; } +.optional { text-decoration: underline dotted; } + +/** Fancy colour display. */ +.colour-ref { + display: inline-block; + width: 0.8em; + height: 0.8em; + margin: 0.1em 0.1em 0.3em 0.1em; /* Terrrible hack to force vertical alignment. */ + border: solid 1px black; + box-sizing: border-box; + vertical-align: middle; +} + +/* styles for prettification of source */ +.highlight .comment { color: #558817; } +.highlight .constant { color: #a8660d; } +.highlight .escape { color: #844631; } +.highlight .keyword { color: #aa5050; font-weight: bold; } +.highlight .library { color: #0e7c6b; } +.highlight .marker { color: #512b1e; background: #fedc56; font-weight: bold; } +.highlight .string { color: #8080ff; } +.highlight .literal-kw { color: #8080ff; } +.highlight .number { color: #f8660d; } +.highlight .operator { color: #2239a8; font-weight: bold; } +.highlight .preprocessor, pre .prepro { color: #a33243; } +.highlight .global { color: #800080; } +.highlight .user-keyword { color: #800080; } +.highlight .prompt { color: #558817; } +.highlight .url { color: #272fc2; text-decoration: underline; } diff --git a/illuaminate.sexp b/illuaminate.sexp index b37f34928..22219f22c 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -1,28 +1,77 @@ ; -*- mode: Lisp;-*- (sources - /src/main/resources/assets/computercraft/lua/bios.lua - /src/main/resources/assets/computercraft/lua/rom/ + /doc/stub/ + /src/main/resources/data/computercraft/lua/bios.lua + /src/main/resources/data/computercraft/lua/rom/ /src/test/resources/test-rom) +(doc + (title "CC: Tweaked") + (index doc/index.md) + (source-link https://github.com/SquidDev-CC/CC-Tweaked/blob/${commit}/${path}#L${line}) + + (library-path + /doc/stub/ + + /src/main/resources/data/computercraft/lua/rom/apis + /src/main/resources/data/computercraft/lua/rom/apis/command + /src/main/resources/data/computercraft/lua/rom/apis/turtle + + /src/main/resources/data/computercraft/lua/rom/modules/main + /src/main/resources/data/computercraft/lua/rom/modules/command + /src/main/resources/data/computercraft/lua/rom/modules/turtle)) + (at / (linters + syntax:string-index + ;; It'd be nice to avoid this, but right now there's a lot of instances of ;; it. -var:set-loop ;; It's useful to name arguments for documentation, so we allow this. It'd ;; be good to find a compromise in the future, but this works for now. - -var:unused-arg)) + -var:unused-arg + + ;; Suppress a couple of documentation comments warnings for now. We'll + ;; hopefully be able to remove them in the future. + -doc:undocumented -doc:undocumented-arg -doc:unresolved-reference + -var:unresolved-member) + (lint + (bracket-spaces + (call no-space) + (function-args no-space) + (parens no-space) + (table space) + (index no-space)))) ;; We disable the unused global linter in bios.lua and the APIs. In the future ;; hopefully we'll get illuaminate to handle this. (at - (/src/main/resources/assets/computercraft/lua/bios.lua - /src/main/resources/assets/computercraft/lua/rom/apis/) + (/src/main/resources/data/computercraft/lua/bios.lua + /src/main/resources/data/computercraft/lua/rom/apis/) (linters -var:unused-global) - (lint - (allow-toplevel-global true))) + (lint (allow-toplevel-global true))) -;; These warnings are broken right now -(at (bios.lua worm.lua) (linters -control:unreachable)) +;; Silence some variable warnings in documentation stubs. +(at /doc/stub + (linters -var:unused-global) + (lint (allow-toplevel-global true))) + +;; Ensure any fully documented modules stay fully documented. +(at + (/src/main/resources/data/computercraft/lua/rom/apis/colors.lua + /src/main/resources/data/computercraft/lua/rom/apis/colours.lua + /src/main/resources/data/computercraft/lua/rom/apis/disk.lua + /src/main/resources/data/computercraft/lua/rom/apis/gps.lua + /src/main/resources/data/computercraft/lua/rom/apis/help.lua + /src/main/resources/data/computercraft/lua/rom/apis/keys.lua + /src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua + /src/main/resources/data/computercraft/lua/rom/apis/parallel.lua + /src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua + /src/main/resources/data/computercraft/lua/rom/apis/rednet.lua + /src/main/resources/data/computercraft/lua/rom/apis/settings.lua + /src/main/resources/data/computercraft/lua/rom/apis/texutils.lua + /src/main/resources/data/computercraft/lua/rom/apis/vector.lua) + (linters doc:undocumented doc:undocumented-arg)) 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..69ed2c857 --- /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:computer" + } + ] + } + }, + "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..2f4cebec8 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..82a335701 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..df587895f --- /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": "forge:dusts/redstone" + } + ] + } + }, + "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..4a511c507 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..9d97d1db1 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..4dc510b4e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..f5238fae6 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..e81b64991 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..a7322e1fa --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..6ead3487a --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..7bc970fc6 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..b8671733b --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..f646f0d05 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..4b348588a --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..40f6ef7de --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..1b23baeec --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..2cf60f3ac --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..fac9be366 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..b1eb4a9b5 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json @@ -0,0 +1,32 @@ +{ + "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" + ] + ] +} \ 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..043371408 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..7c77d28a2 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..e072333c9 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json new file mode 100644 index 000000000..112ba7081 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json new file mode 100644 index 000000000..7b5c315e4 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json new file mode 100644 index 000000000..9f5872d9f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..7e1930b03 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json new file mode 100644 index 000000000..05222ce97 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json new file mode 100644 index 000000000..413e0375d --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..468d54cc9 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json @@ -0,0 +1,43 @@ +{ + "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" + ] + ] +} \ 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..4d40913a7 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json @@ -0,0 +1,43 @@ +{ + "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" + ] + ] +} \ 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..35ab06eea --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..104f9d30e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..5f7431ad7 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json new file mode 100644 index 000000000..c507d2563 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json new file mode 100644 index 000000000..a14901a3e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json new file mode 100644 index 000000000..5dba7dcd6 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..06a10b8ec --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json new file mode 100644 index 000000000..22ccd7e60 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json new file mode 100644 index 000000000..74378a20c --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..c5ddd2003 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..b429cf9e6 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..6ac217096 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..b2bb0df1a --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..b11436e4b --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..5808c4ed5 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..2cf9a608b --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..c36478843 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..664b9f9e8 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..dfd1b4664 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..74c5dac34 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..e54be71d1 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..fe1c547eb --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..afd62779d --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..a6a16729e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..e26cd09cf --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..3d6b54ec4 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..ab64bae40 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json @@ -0,0 +1,35 @@ +{ + "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" + ] + ] +} \ 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..f78501816 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json @@ -0,0 +1,43 @@ +{ + "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" + ] + ] +} \ 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..5941483e3 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json @@ -0,0 +1,43 @@ +{ + "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" + ] + ] +} \ 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/loot_tables/computer_advanced.json b/src/generated/resources/data/computercraft/loot_tables/computer_advanced.json new file mode 100644 index 000000000..09dac48f6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/computer_advanced.json @@ -0,0 +1,30 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/computer_normal.json b/src/generated/resources/data/computercraft/loot_tables/computer_normal.json new file mode 100644 index 000000000..09dac48f6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/computer_normal.json @@ -0,0 +1,30 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/disk_drive.json b/src/generated/resources/data/computercraft/loot_tables/disk_drive.json new file mode 100644 index 000000000..675f3cf78 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/disk_drive.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "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/monitor_advanced.json b/src/generated/resources/data/computercraft/loot_tables/monitor_advanced.json new file mode 100644 index 000000000..e5c1b82b1 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/monitor_advanced.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "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/monitor_normal.json b/src/generated/resources/data/computercraft/loot_tables/monitor_normal.json new file mode 100644 index 000000000..f27f7adcf --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/monitor_normal.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "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/printer.json b/src/generated/resources/data/computercraft/loot_tables/printer.json new file mode 100644 index 000000000..c632c9d67 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/printer.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "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/speaker.json b/src/generated/resources/data/computercraft/loot_tables/speaker.json new file mode 100644 index 000000000..5b6d03f9a --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/speaker.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "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/turtle_advanced.json b/src/generated/resources/data/computercraft/loot_tables/turtle_advanced.json new file mode 100644 index 000000000..09dac48f6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/turtle_advanced.json @@ -0,0 +1,30 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/turtle_normal.json b/src/generated/resources/data/computercraft/loot_tables/turtle_normal.json new file mode 100644 index 000000000..09dac48f6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/turtle_normal.json @@ -0,0 +1,30 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json b/src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json new file mode 100644 index 000000000..02bd68624 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "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/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/loot_tables/wireless_modem_advanced.json new file mode 100644 index 000000000..4f46d4b0f --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "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/wireless_modem_normal.json b/src/generated/resources/data/computercraft/loot_tables/wireless_modem_normal.json new file mode 100644 index 000000000..a9fdb21e7 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "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..357212509 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/cable.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " # ", + "#R#", + " # " + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + } + }, + "result": { + "item": "computercraft:cable", + "count": 6 + } +} \ 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..d004a6c78 --- /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": "forge:ingots/gold" + }, + "R": { + "tag": "forge:dusts/redstone" + }, + "G": { + "tag": "forge: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..c3f71b49b --- /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": "forge:ingots/gold" + }, + "R": { + "item": "minecraft:command_block" + }, + "G": { + "tag": "forge: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..661f4945f --- /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": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + }, + "G": { + "tag": "forge:glass_panes" + } + }, + "result": { + "item": "computercraft:computer_normal" + } +} \ 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..66ce73a90 --- /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": "forge:dusts/redstone" + }, + { + "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..9c064f0fb --- /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": "forge:dusts/redstone" + }, + { + "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..bfd6b21dc --- /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": "forge:dusts/redstone" + }, + { + "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..7fa0ff4be --- /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": "forge:dusts/redstone" + }, + { + "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..ab237e75c --- /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": "forge:dusts/redstone" + }, + { + "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..458ad2a71 --- /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": "forge:dusts/redstone" + }, + { + "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..35147838e --- /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": "forge:dusts/redstone" + }, + { + "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..1f86b573a --- /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": "forge:dusts/redstone" + }, + { + "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..40f55f5a4 --- /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": "forge:dusts/redstone" + }, + { + "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..5ed4b4d72 --- /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": "forge:dusts/redstone" + }, + { + "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..ecc80c9e2 --- /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": "forge:dusts/redstone" + }, + { + "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..94beac68a --- /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": "forge:dusts/redstone" + }, + { + "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..0416fba6e --- /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": "forge:dusts/redstone" + }, + { + "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..99f64b544 --- /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": "forge:dusts/redstone" + }, + { + "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..be1b7fea9 --- /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": "forge:dusts/redstone" + }, + { + "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..48620dbdd --- /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": "forge:dusts/redstone" + }, + { + "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..a217fc712 --- /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": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + } + }, + "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..7588676cd --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/monitor_advanced.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#G#", + "###" + ], + "key": { + "#": { + "tag": "forge:ingots/gold" + }, + "G": { + "tag": "forge: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..2ded57d08 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/monitor_normal.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#G#", + "###" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "G": { + "tag": "forge: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..350a5019b --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json @@ -0,0 +1,19 @@ +{ + "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" + } +} \ 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..8896bd062 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "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" + } +} \ 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..9e007b1cd --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "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" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json new file mode 100644 index 000000000..0cd065680 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:crafting_table" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json new file mode 100644 index 000000000..7b8fa8a24 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_axe" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json new file mode 100644 index 000000000..9514a59cd --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_hoe" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..e28008623 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_pickaxe" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json new file mode 100644 index 000000000..b0ddf3016 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_shovel" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json new file mode 100644 index 000000000..cea0b2a0f --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_sword" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ 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..b8c65358d --- /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": "forge:ingots/gold" + }, + "A": { + "item": "minecraft:golden_apple" + }, + "G": { + "tag": "forge: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..c18f0252a --- /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": "forge:stone" + }, + "A": { + "item": "minecraft:golden_apple" + }, + "G": { + "tag": "forge:glass_panes" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ 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..b5fb937a4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json @@ -0,0 +1,19 @@ +{ + "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" + } +} \ 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..d8e9518e4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "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" + } +} \ 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..736753136 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "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" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json new file mode 100644 index 000000000..dc1ddd884 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:crafting_table" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json new file mode 100644 index 000000000..686d9d890 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_axe" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json new file mode 100644 index 000000000..905a2640a --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_hoe" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..200d15862 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_pickaxe" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json new file mode 100644 index 000000000..fcae256c7 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_shovel" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json new file mode 100644 index 000000000..564dbf7e5 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_sword" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ 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..5f0072676 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/printer.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#D#" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + }, + "D": { + "tag": "forge:dyes" + } + }, + "result": { + "item": "computercraft:printer" + } +} \ 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..c1ede5db7 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/speaker.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#N#", + "#R#" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "N": { + "item": "minecraft:note_block" + }, + "R": { + "tag": "forge:dusts/redstone" + } + }, + "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..6526349af --- /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": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "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..2aea48cae --- /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": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "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..39c434755 --- /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": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "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..f7178ff09 --- /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": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "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..ab2831b56 --- /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": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "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..13c2f694c --- /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": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "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..3f3763457 --- /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": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "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..248f62209 --- /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": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "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..8cab2a90b --- /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": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "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_normal/computercraft/speaker.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json new file mode 100644 index 000000000..28f425aec --- /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": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "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..3af190a52 --- /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": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "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..f387a143d --- /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": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "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..8e8a1dcc9 --- /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": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "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..85a16309d --- /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": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "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..45491a5e8 --- /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": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "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..db9ef1ae6 --- /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": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "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..66f98c2c9 --- /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": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "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..c99c73c03 --- /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": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "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/wired_modem.json b/src/generated/resources/data/computercraft/recipes/wired_modem.json new file mode 100644 index 000000000..7494043b4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wired_modem.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "###" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + } + }, + "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..a274aa73d --- /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": "forge:ingots/gold" + }, + "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..e2041f59e --- /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": "forge:stone" + }, + "E": { + "tag": "forge:ender_pearls" + } + }, + "result": { + "item": "computercraft:wireless_modem_normal" + } +} \ 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/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 99ec296b2..3af6d527e 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -7,7 +7,6 @@ import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.http.AddressRule; -import dan200.computercraft.core.apis.http.websocket.Websocket; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.core.ClientComputerRegistry; @@ -22,6 +21,7 @@ import dan200.computercraft.shared.peripheral.modem.wired.ItemBlockCable; import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem; import dan200.computercraft.shared.peripheral.monitor.BlockMonitor; +import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.printer.BlockPrinter; import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; @@ -88,7 +88,7 @@ public final class ComputerCraft public static long httpMaxDownload = 16 * 1024 * 1024; public static long httpMaxUpload = 4 * 1024 * 1024; public static int httpMaxWebsockets = 4; - public static int httpMaxWebsocketMessage = Websocket.MAX_MESSAGE_SIZE; + public static int httpMaxWebsocketMessage = 128 * 1024; public static boolean enableCommandBlock = false; public static int modem_range = 64; @@ -96,6 +96,7 @@ public final class ComputerCraft public static int modem_rangeDuringStorm = 64; public static int modem_highAltitudeRangeDuringStorm = 384; public static int maxNotesPerTick = 8; + public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST; public static boolean turtlesNeedFuel = true; public static int turtleFuelLimit = 20000; diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java new file mode 100644 index 000000000..5dcf3e964 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java @@ -0,0 +1,81 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.filesystem; + +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.time.Instant; + +/** + * A simple version of {@link BasicFileAttributes}, which provides what information a {@link IMount} already exposes. + */ +final class FileAttributes implements BasicFileAttributes +{ + private static final FileTime EPOCH = FileTime.from( Instant.EPOCH ); + + private final boolean isDirectory; + private final long size; + + FileAttributes( boolean isDirectory, long size ) + { + this.isDirectory = isDirectory; + this.size = size; + } + + @Override + public FileTime lastModifiedTime() + { + return EPOCH; + } + + @Override + public FileTime lastAccessTime() + { + return EPOCH; + } + + @Override + public FileTime creationTime() + { + return EPOCH; + } + + @Override + public boolean isRegularFile() + { + return !isDirectory; + } + + @Override + public boolean isDirectory() + { + return isDirectory; + } + + @Override + public boolean isSymbolicLink() + { + return false; + } + + @Override + public boolean isOther() + { + return false; + } + + @Override + public long size() + { + return size; + } + + @Override + public Object fileKey() + { + return null; + } +} diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java index 703a95911..70a25fe5f 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java @@ -27,7 +27,7 @@ public FileOperationException( @Nullable String filename, @Nonnull String messag this.filename = filename; } - public FileOperationException( String message ) + public FileOperationException( @Nonnull String message ) { super( Objects.requireNonNull( message, "message cannot be null" ) ); this.filename = null; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index 50682a958..258843822 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -12,6 +12,7 @@ import javax.annotation.Nonnull; import java.io.IOException; import java.nio.channels.ReadableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; import java.util.List; /** @@ -76,4 +77,18 @@ public interface IMount */ @Nonnull ReadableByteChannel openForRead( @Nonnull String path ) throws IOException; + + /** + * Get attributes about the given file. + * + * @param path The path to query. + * @return File attributes for the given file. + * @throws IOException If the file does not exist, or attributes could not be fetched. + */ + @Nonnull + default BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + if( !exists( path ) ) throw new FileOperationException( path, "No such file" ); + return new FileAttributes( isDirectory( path ), getSize( path ) ); + } } diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java index 8ec6fabc1..5a52b5ae7 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -13,6 +13,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.channels.WritableByteChannel; +import java.util.OptionalLong; /** * Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)} @@ -74,4 +75,16 @@ public interface IWritableMount extends IMount * @throws IOException If the remaining space could not be computed. */ long getRemainingSpace() throws IOException; + + /** + * Get the capacity of this mount. This should be equal to the size of all files/directories on this mount, minus + * the {@link #getRemainingSpace()}. + * + * @return The capacity of this mount, in bytes. + */ + @Nonnull + default OptionalLong getCapacity() + { + return OptionalLong.empty(); + } } diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index af95acd67..9582baada 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -46,8 +46,17 @@ private static float toGreyscale( double[] rgb ) return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); } + private static int getColour( char c ) + { + int i = "0123456789abcdef".indexOf( c ); + return i < 0 ? 0 : 15 - i; + } + private static void drawChar( Matrix4f transform, IVertexBuilder buffer, float x, float y, int index, float r, float g, float b ) { + // 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; @@ -72,6 +81,24 @@ private static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x buffer.pos( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_END ).endVertex(); } + private static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex ) + { + double[] colour = palette.getColour( getColour( colourIndex ) ); + 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 ); + } + private static void drawBackground( @Nonnull Matrix4f transform, @Nonnull IVertexBuilder renderer, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, @@ -80,56 +107,34 @@ private static void drawBackground( { if( leftMarginSize > 0 ) { - double[] colour = palette.getColour( 15 - "0123456789abcdef".indexOf( backgroundColour.charAt( 0 ) ) ); - 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, renderer, x - leftMarginSize, y, leftMarginSize, height, r, g, b ); + drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) ); } if( rightMarginSize > 0 ) { - double[] colour = palette.getColour( 15 - "0123456789abcdef".indexOf( backgroundColour.charAt( backgroundColour.length() - 1 ) ) ); - 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, renderer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, r, g, b ); + drawQuad( transform, renderer, 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++ ) { - double[] colour = palette.getColour( 15 - "0123456789abcdef".indexOf( backgroundColour.charAt( i ) ) ); - float r, g, b; - if( greyscale ) + char colourIndex = backgroundColour.charAt( i ); + if( colourIndex == blockColour ) continue; + + if( blockColour != '\0' ) { - r = g = b = toGreyscale( colour ); - } - else - { - r = (float) colour[0]; - g = (float) colour[1]; - b = (float) colour[2]; + drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour ); } - drawQuad( transform, renderer, x + i * FONT_WIDTH, y, FONT_WIDTH, height, r, g, b ); + blockColour = colourIndex; + blockStart = i; + } + + if( blockColour != '\0' ) + { + drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour ); } } @@ -172,8 +177,7 @@ public static void drawString( @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize ) { - Minecraft.getInstance().getTextureManager().bindTexture( FONT ); - // TODO: RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + bindFont(); IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); drawString( IDENTITY, ((IRenderTypeBuffer) renderer).getBuffer( TYPE ), x, y, text, textColour, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize ); @@ -258,9 +262,7 @@ public static void drawTerminal( float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize ) { - Minecraft.getInstance().getTextureManager().bindTexture( FONT ); - // TODO: Is this the most sane thing? - RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + bindFont(); IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); IVertexBuilder buffer = renderer.getBuffer( TYPE ); @@ -284,8 +286,7 @@ public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull IRen public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height ) { - Minecraft.getInstance().getTextureManager().bindTexture( FONT ); - RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + bindFont(); IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); drawEmptyTerminal( transform, renderer, x, y, width, height ); @@ -303,6 +304,12 @@ public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull IRenderTyp drawQuad( transform, renderer.getBuffer( Type.BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); } + private static void bindFont() + { + Minecraft.getInstance().getTextureManager().bindTexture( FONT ); + RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + } + private static final class Type extends RenderState { private static final int GL_MODE = GL11.GL_TRIANGLES; diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index 086ebff27..57911646b 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -9,6 +9,7 @@ import dan200.computercraft.client.gui.*; import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; +import dan200.computercraft.client.render.TurtlePlayerRenderer; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; @@ -18,6 +19,7 @@ import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; +import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import net.minecraft.client.gui.ScreenManager; import net.minecraft.client.renderer.RenderType; @@ -26,6 +28,7 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.registry.ClientRegistry; +import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; @@ -51,6 +54,8 @@ public static void setupClient( FMLClientSetupEvent event ) ClientRegistry.bindTileEntityRenderer( TileTurtle.FACTORY_NORMAL, TileEntityTurtleRenderer::new ); ClientRegistry.bindTileEntityRenderer( TileTurtle.FACTORY_ADVANCED, TileEntityTurtleRenderer::new ); // TODO: ClientRegistry.bindTileEntityRenderer( TileCable.FACTORY, x -> new TileEntityCableRenderer() ); + + RenderingRegistry.registerEntityRenderingHandler( TurtlePlayer.TYPE, TurtlePlayerRenderer::new ); } private static void registerContainers() diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index ed4827e52..0eff25b14 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -11,6 +11,7 @@ import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; 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.DirectionUtil; import net.minecraft.client.renderer.*; @@ -92,7 +93,7 @@ public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull M boolean redraw = originTerminal.pollTerminalChanged(); if( originTerminal.buffer == null ) { - originTerminal.createBuffer(); + originTerminal.createBuffer( MonitorRenderer.VBO ); redraw = true; } VertexBuffer vbo = originTerminal.buffer; diff --git a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java new file mode 100644 index 000000000..341c9a591 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java @@ -0,0 +1,37 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.client.render; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.turtle.core.TurtlePlayer; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class TurtlePlayerRenderer extends EntityRenderer +{ + public TurtlePlayerRenderer( EntityRendererManager renderManager ) + { + super( renderManager ); + } + + @Override + public void doRender( @Nonnull TurtlePlayer entity, double x, double y, double z, float entityYaw, float partialTicks ) + { + ComputerCraft.log.error( "Rendering TurtlePlayer on the client side, at {}", entity.getPosition() ); + } + + @Nullable + @Override + protected ResourceLocation getEntityTexture( @Nonnull TurtlePlayer entity ) + { + return null; + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index c99273763..90a866a53 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -22,6 +22,11 @@ import java.io.BufferedWriter; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.util.HashMap; +import java.util.Map; +import java.util.OptionalLong; import java.util.function.Function; import static dan200.computercraft.api.lua.ArgumentHelper.getString; @@ -76,6 +81,8 @@ public String[] getMethodNames() "getFreeSpace", "find", "getDir", + "getCapacity", + "attributes", }; } @@ -315,9 +322,8 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O throw new LuaException( e.getMessage() ); } } - case 14: + case 14: // find { - // find String path = getString( args, 0 ); try { @@ -329,15 +335,50 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O throw new LuaException( e.getMessage() ); } } - case 15: + case 15: // getDir { - // getDir String path = getString( args, 0 ); return new Object[] { FileSystem.getDirectory( path ) }; } + case 16: // getCapacity + { + String path = getString( args, 0 ); + try + { + OptionalLong capacity = m_fileSystem.getCapacity( path ); + return new Object[] { capacity.isPresent() ? capacity.getAsLong() : null }; + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + case 17: // attributes + { + String path = getString( args, 0 ); + try + { + BasicFileAttributes attributes = m_fileSystem.getAttributes( path ); + Map result = new HashMap<>(); + result.put( "modification", getFileTime( attributes.lastModifiedTime() ) ); + result.put( "created", getFileTime( attributes.creationTime() ) ); + result.put( "size", attributes.isDirectory() ? 0 : attributes.size() ); + result.put( "isDir", attributes.isDirectory() ); + return new Object[] { result }; + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } default: assert false; return null; } } + + private static long getFileTime( FileTime time ) + { + return time == null ? 0 : time.toMillis(); + } } diff --git a/src/main/java/dan200/computercraft/core/apis/FastLuaException.java b/src/main/java/dan200/computercraft/core/apis/FastLuaException.java new file mode 100644 index 000000000..6ef64f275 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/FastLuaException.java @@ -0,0 +1,35 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.apis; + +import dan200.computercraft.api.lua.LuaException; + +import javax.annotation.Nullable; + +/** + * A Lua exception which does not contain its stack trace. + */ +public class FastLuaException extends LuaException +{ + private static final long serialVersionUID = 5957864899303561143L; + + public FastLuaException( @Nullable String message ) + { + super( message ); + } + + public FastLuaException( @Nullable String message, int level ) + { + super( message, level ); + } + + @Override + public synchronized Throwable fillInStackTrace() + { + return this; + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java index 00b5ebf8d..0a4315960 100644 --- a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java +++ b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java @@ -18,6 +18,8 @@ public interface IAPIEnvironment { + String TIMER_EVENT = "timer"; + @FunctionalInterface interface IPeripheralChangeListener { @@ -64,6 +66,10 @@ interface IPeripheralChangeListener void setLabel( @Nullable String label ); + int startTimer( long ticks ); + + void cancelTimer( int id ); + void addTrackingChange( @Nonnull TrackingField field, long change ); default void addTrackingChange( @Nonnull TrackingField field ) diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index e1bc5c1ab..6ccd51730 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -9,6 +9,8 @@ import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.shared.util.StringUtil; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import javax.annotation.Nonnull; import java.time.Instant; @@ -24,24 +26,12 @@ public class OSAPI implements ILuaAPI { private IAPIEnvironment m_apiEnvironment; - private final Map m_timers; - private final Map m_alarms; + private final Int2ObjectMap m_alarms = new Int2ObjectOpenHashMap<>(); private int m_clock; private double m_time; private int m_day; - private int m_nextTimerToken; - private int m_nextAlarmToken; - - private static class Timer - { - int m_ticksLeft; - - Timer( int ticksLeft ) - { - m_ticksLeft = ticksLeft; - } - } + private int m_nextAlarmToken = 0; private static class Alarm implements Comparable { @@ -66,10 +56,6 @@ public int compareTo( @Nonnull Alarm o ) public OSAPI( IAPIEnvironment environment ) { m_apiEnvironment = environment; - m_nextTimerToken = 0; - m_nextAlarmToken = 0; - m_timers = new HashMap<>(); - m_alarms = new HashMap<>(); } // ILuaAPI implementation @@ -87,11 +73,6 @@ public void startup() m_day = m_apiEnvironment.getComputerEnvironment().getDay(); m_clock = 0; - synchronized( m_timers ) - { - m_timers.clear(); - } - synchronized( m_alarms ) { m_alarms.clear(); @@ -101,26 +82,7 @@ public void startup() @Override public void update() { - synchronized( m_timers ) - { - // Update the clock - m_clock++; - - // Countdown all of our active timers - Iterator> it = m_timers.entrySet().iterator(); - while( it.hasNext() ) - { - Map.Entry entry = it.next(); - Timer timer = entry.getValue(); - timer.m_ticksLeft--; - if( timer.m_ticksLeft <= 0 ) - { - // Queue the "timer" event - queueLuaEvent( "timer", new Object[] { entry.getKey() } ); - it.remove(); - } - } - } + m_clock++; // Wait for all of our alarms synchronized( m_alarms ) @@ -133,10 +95,10 @@ public void update() if( time > previousTime || day > previousDay ) { double now = m_day * 24.0 + m_time; - Iterator> it = m_alarms.entrySet().iterator(); + Iterator> it = m_alarms.int2ObjectEntrySet().iterator(); while( it.hasNext() ) { - Map.Entry entry = it.next(); + Int2ObjectMap.Entry entry = it.next(); Alarm alarm = entry.getValue(); double t = alarm.m_day * 24.0 + alarm.m_time; if( now >= t ) @@ -155,11 +117,6 @@ public void update() @Override public void shutdown() { - synchronized( m_timers ) - { - m_timers.clear(); - } - synchronized( m_alarms ) { m_alarms.clear(); @@ -229,11 +186,8 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O { // startTimer double timer = getFiniteDouble( args, 0 ); - synchronized( m_timers ) - { - m_timers.put( m_nextTimerToken, new Timer( (int) Math.round( timer / 0.05 ) ) ); - return new Object[] { m_nextTimerToken++ }; - } + int id = m_apiEnvironment.startTimer( Math.round( timer / 0.05 ) ); + return new Object[] { id }; } case 2: { @@ -278,10 +232,7 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O return null; } case 10: // clock - synchronized( m_timers ) - { - return new Object[] { m_clock * 0.05 }; - } + return new Object[] { m_clock * 0.05 }; case 11: { // time @@ -345,10 +296,7 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O { // cancelTimer int token = getInt( args, 0 ); - synchronized( m_timers ) - { - m_timers.remove( token ); - } + m_apiEnvironment.cancelTimer( token ); return null; } case 14: diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index 81de3d594..2d07d58bc 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -366,22 +366,30 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O String methodName = getString( args, 1 ); Object[] methodArgs = Arrays.copyOfRange( args, 2, args.length ); - if( side != null ) + if( side == null ) throw new LuaException( "No peripheral attached" ); + + PeripheralWrapper p; + synchronized( m_peripherals ) { - PeripheralWrapper p; - synchronized( m_peripherals ) - { - p = m_peripherals[side.ordinal()]; - } - if( p != null ) - { - return p.call( context, methodName, methodArgs ); - } + p = m_peripherals[side.ordinal()]; + } + if( p == null ) throw new LuaException( "No peripheral attached" ); + + try + { + return p.call( context, methodName, methodArgs ); + } + catch( LuaException e ) + { + // We increase the error level by one in order to shift the error level to where peripheral.call was + // invoked. It would be possible to do it in Lua code, but would add significantly more overhead. + if( e.getLevel() > 0 ) throw new FastLuaException( e.getMessage(), e.getLevel() + 1 ); + throw e; } - throw new LuaException( "No peripheral attached" ); } default: return null; } } + } diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java index c088f09d2..5e1562d04 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java @@ -40,7 +40,11 @@ */ public class Websocket extends Resource { - public static final int MAX_MESSAGE_SIZE = 64 * 1024; + /** + * We declare the maximum size to be 2^30 bytes. While messages can be much longer, we set an arbitrary limit as + * working with larger messages (especially within a Lua VM) is absurd. + */ + public static final int MAX_MESSAGE_SIZE = 1 << 30; static final String SUCCESS_EVENT = "websocket_success"; static final String FAILURE_EVENT = "websocket_failure"; diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java index 976b526c2..8433d30c3 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java @@ -7,6 +7,7 @@ import com.google.common.base.Objects; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.ArgumentHelper; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaObject; import dan200.computercraft.api.lua.LuaException; @@ -23,6 +24,7 @@ import java.util.Arrays; import static dan200.computercraft.api.lua.ArgumentHelper.optBoolean; +import static dan200.computercraft.core.apis.IAPIEnvironment.TIMER_EVENT; import static dan200.computercraft.core.apis.http.websocket.Websocket.CLOSE_EVENT; import static dan200.computercraft.core.apis.http.websocket.Websocket.MESSAGE_EVENT; @@ -53,7 +55,21 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O switch( method ) { case 0: // receive + { checkOpen(); + int timeoutId; + if( arguments.length <= 0 || arguments[0] == null ) + { + // We do this rather odd argument validation to ensure we can tell the difference between a + // negative timeout and an absent one. + timeoutId = -1; + } + else + { + double timeout = ArgumentHelper.getFiniteDouble( arguments, 0 ); + timeoutId = websocket.environment().startTimer( Math.round( timeout / 0.05 ) ); + } + while( true ) { Object[] event = context.pullEvent( null ); @@ -63,9 +79,17 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O } else if( event.length >= 2 && Objects.equal( event[0], CLOSE_EVENT ) && Objects.equal( event[1], websocket.address() ) && closed ) { + // If the socket is closed abort. + return null; + } + else if( event.length >= 2 && timeoutId != -1 && Objects.equal( event[0], TIMER_EVENT ) + && event[1] instanceof Number && ((Number) event[1]).intValue() == timeoutId ) + { + // If we received a matching timer event then abort. return null; } } + } case 1: // send { diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index 010e408d0..55f02086d 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -181,7 +181,7 @@ public void tick() executor.tick(); // Update the environment's internal state. - internalEnvironment.update(); + internalEnvironment.tick(); // Propagate the environment's output to the world. if( internalEnvironment.updateOutput() ) externalOutputChanged.set( true ); diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java index b3ccd2718..811168b80 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java @@ -426,6 +426,7 @@ private void turnOn() throws InterruptedException } // Init APIs + computer.getEnvironment().reset(); for( ILuaAPI api : apis ) api.startup(); // Init lua @@ -469,6 +470,7 @@ private void shutdown() throws InterruptedException // Shutdown our APIs for( ILuaAPI api : apis ) api.shutdown(); + computer.getEnvironment().reset(); // Unload filesystem if( fileSystem != null ) diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java index 35a79ee4d..819997c92 100644 --- a/src/main/java/dan200/computercraft/core/computer/Environment.java +++ b/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.core.computer; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IWorkMonitor; import dan200.computercraft.core.apis.IAPIEnvironment; @@ -12,9 +13,12 @@ import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.core.tracking.TrackingField; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import javax.annotation.Nonnull; import java.util.Arrays; +import java.util.Iterator; /** * Represents the "environment" that a {@link Computer} exists in. @@ -53,6 +57,9 @@ public final class Environment implements IAPIEnvironment private final IPeripheral[] peripherals = new IPeripheral[ComputerSide.COUNT]; private IPeripheralChangeListener peripheralListener = null; + private final Int2ObjectMap timers = new Int2ObjectOpenHashMap<>(); + private int nextTimerToken = 0; + Environment( Computer computer ) { this.computer = computer; @@ -198,17 +205,47 @@ public void setBundledRedstoneInput( ComputerSide side, int combination ) } /** - * Called on the main thread to update the internal state of the computer. + * Called when the computer starts up or shuts down, to reset any internal state. * - * This just queues a {@code redstone} event if the input has changed. + * @see ILuaAPI#startup() + * @see ILuaAPI#shutdown() */ - void update() + void reset() + { + synchronized( timers ) + { + timers.clear(); + } + } + + /** + * Called on the main thread to update the internal state of the computer. + */ + void tick() { if( inputChanged ) { inputChanged = false; queueEvent( "redstone", null ); } + + synchronized( timers ) + { + // Countdown all of our active timers + Iterator> it = timers.int2ObjectEntrySet().iterator(); + while( it.hasNext() ) + { + Int2ObjectMap.Entry entry = it.next(); + Timer timer = entry.getValue(); + timer.ticksLeft--; + if( timer.ticksLeft <= 0 ) + { + // Queue the "timer" event + queueEvent( TIMER_EVENT, new Object[] { entry.getIntKey() } ); + it.remove(); + } + } + } } /** @@ -303,9 +340,38 @@ public void setLabel( String label ) computer.setLabel( label ); } + @Override + public int startTimer( long ticks ) + { + synchronized( timers ) + { + timers.put( nextTimerToken, new Timer( ticks ) ); + return nextTimerToken++; + } + } + + @Override + public void cancelTimer( int id ) + { + synchronized( timers ) + { + timers.remove( id ); + } + } + @Override public void addTrackingChange( @Nonnull TrackingField field, long change ) { Tracking.addValue( computer, field, change ); } + + private static class Timer + { + long ticksLeft; + + Timer( long ticksLeft ) + { + this.ticksLeft = ticksLeft; + } + } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java index 94630a90e..ffd7db5cf 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java @@ -11,6 +11,7 @@ import javax.annotation.Nonnull; import java.io.IOException; import java.nio.channels.ReadableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -126,4 +127,19 @@ public ReadableByteChannel openForRead( @Nonnull String path ) throws IOExceptio } throw new FileOperationException( path, "No such file" ); } + + @Nonnull + @Override + public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + for( int i = m_parts.length - 1; i >= 0; --i ) + { + IMount part = m_parts[i]; + if( part.exists( path ) && !part.isDirectory( path ) ) + { + return part.getAttributes( path ); + } + } + throw new FileOperationException( path, "No such file" ); + } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java index 414fdef75..c1d2a0af6 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.filesystem; import com.google.common.collect.Sets; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IWritableMount; @@ -14,11 +15,11 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.*; -import java.nio.file.Files; -import java.nio.file.OpenOption; -import java.nio.file.StandardOpenOption; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; import java.util.Collections; import java.util.List; +import java.util.OptionalLong; import java.util.Set; public class FileMount implements IWritableMount @@ -211,6 +212,19 @@ public ReadableByteChannel openForRead( @Nonnull String path ) throws IOExceptio throw new FileOperationException( path, "No such file" ); } + @Nonnull + @Override + public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + if( created() ) + { + File file = getRealPath( path ); + if( file.exists() ) return Files.readAttributes( file.toPath(), BasicFileAttributes.class ); + } + + throw new FileOperationException( path, "No such file" ); + } + // IWritableMount implementation @Override @@ -331,6 +345,13 @@ public long getRemainingSpace() return Math.max( m_capacity - m_usedSpace, 0 ); } + @Nonnull + @Override + public OptionalLong getCapacity() + { + return OptionalLong.of( m_capacity - MINIMUM_FILE_SIZE ); + } + private File getRealPath( String path ) { return new File( m_rootPath, path ); @@ -353,23 +374,46 @@ private void create() throws IOException } } + private static class Visitor extends SimpleFileVisitor + { + long size; + + @Override + public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs ) + { + size += MINIMUM_FILE_SIZE; + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) + { + size += Math.max( attrs.size(), MINIMUM_FILE_SIZE ); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed( Path file, IOException exc ) + { + ComputerCraft.log.error( "Error computing file size for {}", file, exc ); + return FileVisitResult.CONTINUE; + } + } + private static long measureUsedSpace( File file ) { if( !file.exists() ) return 0; - if( file.isDirectory() ) + try { - long size = MINIMUM_FILE_SIZE; - String[] contents = file.list(); - for( String content : contents ) - { - size += measureUsedSpace( new File( file, content ) ); - } - return size; + Visitor visitor = new Visitor(); + Files.walkFileTree( file.toPath(), visitor ); + return visitor.size; } - else + catch( IOException e ) { - return Math.max( file.length(), MINIMUM_FILE_SIZE ); + ComputerCraft.log.error( "Error computing file size for {}", file, e ); + return 0; } } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index b9819b587..0403f98ac 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -7,7 +7,6 @@ import com.google.common.io.ByteStreams; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IFileSystem; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; @@ -23,309 +22,23 @@ import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.nio.file.AccessDeniedException; +import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; public class FileSystem { - private static class MountWrapper - { - private String m_label; - private String m_location; - - private IMount m_mount; - private IWritableMount m_writableMount; - - MountWrapper( String label, String location, IMount mount ) - { - m_label = label; - m_location = location; - m_mount = mount; - m_writableMount = null; - } - - MountWrapper( String label, String location, IWritableMount mount ) - { - this( label, location, (IMount) mount ); - m_writableMount = mount; - } - - public String getLabel() - { - return m_label; - } - - public String getLocation() - { - return m_location; - } - - public long getFreeSpace() - { - if( m_writableMount == null ) - { - return 0; - } - - try - { - return m_writableMount.getRemainingSpace(); - } - catch( IOException e ) - { - return 0; - } - } - - public boolean isReadOnly( String path ) - { - return m_writableMount == null; - } - - // IMount forwarders: - - public boolean exists( String path ) throws FileSystemException - { - path = toLocal( path ); - try - { - return m_mount.exists( path ); - } - catch( IOException e ) - { - throw new FileSystemException( e.getMessage() ); - } - } - - public boolean isDirectory( String path ) throws FileSystemException - { - path = toLocal( path ); - try - { - return m_mount.exists( path ) && m_mount.isDirectory( path ); - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public void list( String path, List contents ) throws FileSystemException - { - path = toLocal( path ); - try - { - if( m_mount.exists( path ) && m_mount.isDirectory( path ) ) - { - m_mount.list( path, contents ); - } - else - { - throw localExceptionOf( path, "Not a directory" ); - } - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public long getSize( String path ) throws FileSystemException - { - path = toLocal( path ); - try - { - if( m_mount.exists( path ) ) - { - if( m_mount.isDirectory( path ) ) - { - return 0; - } - else - { - return m_mount.getSize( path ); - } - } - else - { - throw localExceptionOf( path, "No such file" ); - } - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public ReadableByteChannel openForRead( String path ) throws FileSystemException - { - path = toLocal( path ); - try - { - if( m_mount.exists( path ) && !m_mount.isDirectory( path ) ) - { - return m_mount.openForRead( path ); - } - else - { - throw localExceptionOf( path, "No such file" ); - } - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - // IWritableMount forwarders: - - public void makeDirectory( String path ) throws FileSystemException - { - if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); - - path = toLocal( path ); - try - { - if( m_mount.exists( path ) ) - { - if( !m_mount.isDirectory( path ) ) throw localExceptionOf( path, "File exists" ); - } - else - { - m_writableMount.makeDirectory( path ); - } - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public void delete( String path ) throws FileSystemException - { - if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); - - try - { - path = toLocal( path ); - if( m_mount.exists( path ) ) - { - m_writableMount.delete( path ); - } - } - catch( AccessDeniedException e ) - { - throw new FileSystemException( "Access denied" ); - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public WritableByteChannel openForWrite( String path ) throws FileSystemException - { - if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); - - path = toLocal( path ); - try - { - if( m_mount.exists( path ) && m_mount.isDirectory( path ) ) - { - throw localExceptionOf( path, "Cannot write to directory" ); - } - else - { - if( !path.isEmpty() ) - { - String dir = getDirectory( path ); - if( !dir.isEmpty() && !m_mount.exists( path ) ) - { - m_writableMount.makeDirectory( dir ); - } - } - return m_writableMount.openForWrite( path ); - } - } - catch( AccessDeniedException e ) - { - throw new FileSystemException( "Access denied" ); - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public WritableByteChannel openForAppend( String path ) throws FileSystemException - { - if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); - - path = toLocal( path ); - try - { - if( !m_mount.exists( path ) ) - { - if( !path.isEmpty() ) - { - String dir = getDirectory( path ); - if( !dir.isEmpty() && !m_mount.exists( path ) ) - { - m_writableMount.makeDirectory( dir ); - } - } - return m_writableMount.openForWrite( path ); - } - else if( m_mount.isDirectory( path ) ) - { - throw localExceptionOf( path, "Cannot write to directory" ); - } - else - { - return m_writableMount.openForAppend( path ); - } - } - catch( AccessDeniedException e ) - { - throw new FileSystemException( "Access denied" ); - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - private String toLocal( String path ) - { - return FileSystem.toLocal( path, m_location ); - } - - private FileSystemException localExceptionOf( IOException e ) - { - if( !m_location.isEmpty() && e instanceof FileOperationException ) - { - FileOperationException ex = (FileOperationException) e; - if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() ); - } - - return new FileSystemException( e.getMessage() ); - } - - private FileSystemException localExceptionOf( String path, String message ) - { - if( !m_location.isEmpty() ) path = path.isEmpty() ? m_location : m_location + "/" + path; - return exceptionOf( path, message ); - } - - private static FileSystemException exceptionOf( String path, String message ) - { - return new FileSystemException( "/" + path + ": " + message ); - } - } + /** + * Maximum depth that {@link #copyRecursive(String, MountWrapper, String, MountWrapper, int)} will descend into. + * + * This is a pretty arbitrary value, though hopefully it is large enough that it'll never be normally hit. This + * exists to prevent it overflowing if it ever gets into an infinite loop. + */ + private static final int MAX_COPY_DEPTH = 128; private final FileSystemWrapperMount m_wrapper = new FileSystemWrapperMount( this ); - private final Map m_mounts = new HashMap<>(); + private final Map mounts = new HashMap<>(); private final HashMap>, ChannelWrapper> m_openFiles = new HashMap<>(); private final ReferenceQueue> m_openFileQueue = new ReferenceQueue<>(); @@ -355,10 +68,7 @@ public synchronized void mount( String label, String location, IMount mount ) th { if( mount == null ) throw new NullPointerException(); location = sanitizePath( location ); - if( location.contains( ".." ) ) - { - throw new FileSystemException( "Cannot mount below the root" ); - } + if( location.contains( ".." ) ) throw new FileSystemException( "Cannot mount below the root" ); mount( new MountWrapper( label, location, mount ) ); } @@ -379,14 +89,13 @@ public synchronized void mountWritable( String label, String location, IWritable private synchronized void mount( MountWrapper wrapper ) { String location = wrapper.getLocation(); - m_mounts.remove( location ); - m_mounts.put( location, wrapper ); + mounts.remove( location ); + mounts.put( location, wrapper ); } public synchronized void unmount( String path ) { - path = sanitizePath( path ); - m_mounts.remove( path ); + mounts.remove( sanitizePath( path ) ); } public synchronized String combine( String path, String childPath ) @@ -430,27 +139,20 @@ public static String getDirectory( String path ) public static String getName( String path ) { path = sanitizePath( path, true ); - if( path.isEmpty() ) - { - return "root"; - } + if( path.isEmpty() ) return "root"; int lastSlash = path.lastIndexOf( '/' ); - if( lastSlash >= 0 ) - { - return path.substring( lastSlash + 1 ); - } - else - { - return path; - } + return lastSlash >= 0 ? path.substring( lastSlash + 1 ) : path; } public synchronized long getSize( String path ) throws FileSystemException { - path = sanitizePath( path ); - MountWrapper mount = getMount( path ); - return mount.getSize( path ); + return getMount( sanitizePath( path ) ).getSize( sanitizePath( path ) ); + } + + public synchronized BasicFileAttributes getAttributes( String path ) throws FileSystemException + { + return getMount( sanitizePath( path ) ).getAttributes( sanitizePath( path ) ); } public synchronized String[] list( String path ) throws FileSystemException @@ -463,7 +165,7 @@ public synchronized String[] list( String path ) throws FileSystemException mount.list( path, list ); // Add any mounts that are mounted at this location - for( MountWrapper otherMount : m_mounts.values() ) + for( MountWrapper otherMount : mounts.values() ) { if( getDirectory( otherMount.getLocation() ).equals( path ) ) { @@ -611,15 +313,13 @@ public synchronized void copy( String sourcePath, String destPath ) throws FileS { throw new FileSystemException( "/" + sourcePath + ": Can't copy a directory inside itself" ); } - copyRecursive( sourcePath, getMount( sourcePath ), destPath, getMount( destPath ) ); + copyRecursive( sourcePath, getMount( sourcePath ), destPath, getMount( destPath ), 0 ); } - private synchronized void copyRecursive( String sourcePath, MountWrapper sourceMount, String destinationPath, MountWrapper destinationMount ) throws FileSystemException + private synchronized void copyRecursive( String sourcePath, MountWrapper sourceMount, String destinationPath, MountWrapper destinationMount, int depth ) throws FileSystemException { - if( !sourceMount.exists( sourcePath ) ) - { - return; - } + if( !sourceMount.exists( sourcePath ) ) return; + if( depth >= MAX_COPY_DEPTH ) throw new FileSystemException( "Too many directories to copy" ); if( sourceMount.isDirectory( sourcePath ) ) { @@ -634,7 +334,8 @@ private synchronized void copyRecursive( String sourcePath, MountWrapper sourceM { copyRecursive( combine( sourcePath, child ), sourceMount, - combine( destinationPath, child ), destinationMount + combine( destinationPath, child ), destinationMount, + depth + 1 ); } } @@ -726,17 +427,25 @@ public synchronized FileSystemWrapper openForWrite( Str return null; } - public long getFreeSpace( String path ) throws FileSystemException + public synchronized long getFreeSpace( String path ) throws FileSystemException { path = sanitizePath( path ); MountWrapper mount = getMount( path ); return mount.getFreeSpace(); } - private MountWrapper getMount( String path ) throws FileSystemException + @Nonnull + public synchronized OptionalLong getCapacity( String path ) throws FileSystemException + { + path = sanitizePath( path ); + MountWrapper mount = getMount( path ); + return mount.getCapacity(); + } + + private synchronized MountWrapper getMount( String path ) throws FileSystemException { // Return the deepest mount that contains a given path - Iterator it = m_mounts.values().iterator(); + Iterator it = mounts.values().iterator(); MountWrapper match = null; int matchLength = 999; while( it.hasNext() ) @@ -854,8 +563,8 @@ else if( part.length() >= 255 ) public static boolean contains( String pathA, String pathB ) { - pathA = sanitizePath( pathA ); - pathB = sanitizePath( pathB ); + pathA = sanitizePath( pathA ).toLowerCase( Locale.ROOT ); + pathB = sanitizePath( pathB ).toLowerCase( Locale.ROOT ); if( pathB.equals( ".." ) ) { diff --git a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java index 874a3d536..d169e8717 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java @@ -23,6 +23,9 @@ import java.lang.ref.WeakReference; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.time.Instant; import java.util.Enumeration; import java.util.HashMap; import java.util.List; @@ -213,6 +216,20 @@ public ReadableByteChannel openForRead( @Nonnull String path ) throws IOExceptio throw new FileOperationException( path, "No such file" ); } + @Nonnull + @Override + public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + FileEntry file = get( path ); + if( file != null ) + { + ZipEntry entry = zip.getEntry( file.path ); + if( entry != null ) return new ZipEntryAttributes( entry ); + } + + throw new FileOperationException( path, "No such file" ); + } + private static class FileEntry { String path; @@ -253,4 +270,76 @@ private static void cleanup() Reference next; while( (next = MOUNT_QUEUE.poll()) != null ) IoUtil.closeQuietly( ((MountReference) next).file ); } + + private static class ZipEntryAttributes implements BasicFileAttributes + { + private final ZipEntry entry; + + ZipEntryAttributes( ZipEntry entry ) + { + this.entry = entry; + } + + @Override + public FileTime lastModifiedTime() + { + return orEpoch( entry.getLastModifiedTime() ); + } + + @Override + public FileTime lastAccessTime() + { + return orEpoch( entry.getLastAccessTime() ); + } + + @Override + public FileTime creationTime() + { + FileTime time = entry.getCreationTime(); + return time == null ? lastModifiedTime() : time; + } + + @Override + public boolean isRegularFile() + { + return !entry.isDirectory(); + } + + @Override + public boolean isDirectory() + { + return entry.isDirectory(); + } + + @Override + public boolean isSymbolicLink() + { + return false; + } + + @Override + public boolean isOther() + { + return false; + } + + @Override + public long size() + { + return entry.getSize(); + } + + @Override + public Object fileKey() + { + return null; + } + + private static final FileTime EPOCH = FileTime.from( Instant.EPOCH ); + + private static FileTime orEpoch( FileTime time ) + { + return time == null ? EPOCH : time; + } + } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java new file mode 100644 index 000000000..5cc4ee958 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java @@ -0,0 +1,312 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.filesystem; + +import dan200.computercraft.api.filesystem.FileOperationException; +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.api.filesystem.IWritableMount; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.nio.file.AccessDeniedException; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.List; +import java.util.OptionalLong; + +class MountWrapper +{ + private String label; + private String location; + + private IMount mount; + private IWritableMount writableMount; + + MountWrapper( String label, String location, IMount mount ) + { + this.label = label; + this.location = location; + this.mount = mount; + writableMount = null; + } + + MountWrapper( String label, String location, IWritableMount mount ) + { + this( label, location, (IMount) mount ); + writableMount = mount; + } + + public String getLabel() + { + return label; + } + + public String getLocation() + { + return location; + } + + public long getFreeSpace() + { + if( writableMount == null ) return 0; + + try + { + return writableMount.getRemainingSpace(); + } + catch( IOException e ) + { + return 0; + } + } + + public OptionalLong getCapacity() + { + return writableMount == null ? OptionalLong.empty() : writableMount.getCapacity(); + } + + public boolean isReadOnly( String path ) + { + return writableMount == null; + } + + public boolean exists( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + return mount.exists( path ); + } + catch( IOException e ) + { + throw new FileSystemException( e.getMessage() ); + } + } + + public boolean isDirectory( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + return mount.exists( path ) && mount.isDirectory( path ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public void list( String path, List contents ) throws FileSystemException + { + path = toLocal( path ); + try + { + if( !mount.exists( path ) || !mount.isDirectory( path ) ) + { + throw localExceptionOf( path, "Not a directory" ); + } + + mount.list( path, contents ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public long getSize( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + if( !mount.exists( path ) ) throw localExceptionOf( path, "No such file" ); + return mount.isDirectory( path ) ? 0 : mount.getSize( path ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + @Nonnull + public BasicFileAttributes getAttributes( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + if( !mount.exists( path ) ) throw localExceptionOf( path, "No such file" ); + return mount.getAttributes( path ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public ReadableByteChannel openForRead( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + if( mount.exists( path ) && !mount.isDirectory( path ) ) + { + return mount.openChannelForRead( path ); + } + else + { + throw localExceptionOf( path, "No such file" ); + } + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public void makeDirectory( String path ) throws FileSystemException + { + if( writableMount == null ) throw exceptionOf( path, "Access denied" ); + + path = toLocal( path ); + try + { + if( mount.exists( path ) ) + { + if( !mount.isDirectory( path ) ) throw localExceptionOf( path, "File exists" ); + } + else + { + writableMount.makeDirectory( path ); + } + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public void delete( String path ) throws FileSystemException + { + if( writableMount == null ) throw exceptionOf( path, "Access denied" ); + + try + { + path = toLocal( path ); + if( mount.exists( path ) ) + { + writableMount.delete( path ); + } + } + catch( AccessDeniedException e ) + { + throw new FileSystemException( "Access denied" ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public WritableByteChannel openForWrite( String path ) throws FileSystemException + { + if( writableMount == null ) throw exceptionOf( path, "Access denied" ); + + path = toLocal( path ); + try + { + if( mount.exists( path ) && mount.isDirectory( path ) ) + { + throw localExceptionOf( path, "Cannot write to directory" ); + } + else + { + if( !path.isEmpty() ) + { + String dir = FileSystem.getDirectory( path ); + if( !dir.isEmpty() && !mount.exists( path ) ) + { + writableMount.makeDirectory( dir ); + } + } + return writableMount.openChannelForWrite( path ); + } + } + catch( AccessDeniedException e ) + { + throw new FileSystemException( "Access denied" ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public WritableByteChannel openForAppend( String path ) throws FileSystemException + { + if( writableMount == null ) throw exceptionOf( path, "Access denied" ); + + path = toLocal( path ); + try + { + if( !mount.exists( path ) ) + { + if( !path.isEmpty() ) + { + String dir = FileSystem.getDirectory( path ); + if( !dir.isEmpty() && !mount.exists( path ) ) + { + writableMount.makeDirectory( dir ); + } + } + return writableMount.openChannelForWrite( path ); + } + else if( mount.isDirectory( path ) ) + { + throw localExceptionOf( path, "Cannot write to directory" ); + } + else + { + return writableMount.openChannelForAppend( path ); + } + } + catch( AccessDeniedException e ) + { + throw new FileSystemException( "Access denied" ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + private String toLocal( String path ) + { + return FileSystem.toLocal( path, location ); + } + + private FileSystemException localExceptionOf( IOException e ) + { + if( !location.isEmpty() && e instanceof FileOperationException ) + { + FileOperationException ex = (FileOperationException) e; + if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() ); + } + + return new FileSystemException( e.getMessage() ); + } + + private FileSystemException localExceptionOf( String path, String message ) + { + if( !location.isEmpty() ) path = path.isEmpty() ? location : location + "/" + path; + return exceptionOf( path, message ); + } + + private static FileSystemException exceptionOf( String path, String message ) + { + return new FileSystemException( "/" + path + ": " + message ); + } +} diff --git a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java index e59b22878..68d2999ee 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java @@ -10,61 +10,60 @@ import javax.annotation.Nonnull; import java.io.IOException; import java.nio.channels.ReadableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; import java.util.List; public class SubMount implements IMount { - private IMount m_parent; - private String m_subPath; + private IMount parent; + private String subPath; public SubMount( IMount parent, String subPath ) { - m_parent = parent; - m_subPath = subPath; + this.parent = parent; + this.subPath = subPath; } - // IMount implementation - @Override public boolean exists( @Nonnull String path ) throws IOException { - return m_parent.exists( getFullPath( path ) ); + return parent.exists( getFullPath( path ) ); } @Override public boolean isDirectory( @Nonnull String path ) throws IOException { - return m_parent.isDirectory( getFullPath( path ) ); + return parent.isDirectory( getFullPath( path ) ); } @Override public void list( @Nonnull String path, @Nonnull List contents ) throws IOException { - m_parent.list( getFullPath( path ), contents ); + parent.list( getFullPath( path ), contents ); } @Override public long getSize( @Nonnull String path ) throws IOException { - return m_parent.getSize( getFullPath( path ) ); + return parent.getSize( getFullPath( path ) ); } @Nonnull @Override public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { - return m_parent.openForRead( getFullPath( path ) ); + return parent.openForRead( getFullPath( path ) ); + } + + @Nonnull + @Override + public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + return parent.getAttributes( getFullPath( path ) ); } private String getFullPath( String path ) { - if( path.isEmpty() ) - { - return m_subPath; - } - else - { - return m_subPath + "/" + path; - } + return path.isEmpty() ? subPath : subPath + "/" + path; } } diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 08c3231f0..8e5e88bb0 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -92,6 +92,7 @@ public CobaltLuaMachine( Computer computer, TimeoutState timeout ) m_globals.load( state, new MathLib() ); m_globals.load( state, new CoroutineLib() ); m_globals.load( state, new Bit32Lib() ); + m_globals.load( state, new Utf8Lib() ); if( ComputerCraft.debug_enable ) m_globals.load( state, new DebugLib() ); // Remove globals we don't want to expose 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..69ef83b78 --- /dev/null +++ b/src/main/java/dan200/computercraft/data/Generators.java @@ -0,0 +1,28 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; +import net.minecraft.data.DataGenerator; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; + +@Mod.EventBusSubscriber( bus = Mod.EventBusSubscriber.Bus.MOD ) +public class Generators +{ + @SubscribeEvent + public static void gather( GatherDataEvent event ) + { + ComputerCraftProxyCommon.registerLoot(); + + DataGenerator generator = event.getGenerator(); + generator.addProvider( new Recipes( generator ) ); + generator.addProvider( new LootTables( generator ) ); + generator.addProvider( new Tags( generator ) ); + } +} 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..54b47c42f --- /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-2020. 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.DirectoryCache; +import net.minecraft.data.IDataProvider; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.LootTable; +import net.minecraft.world.storage.loot.LootTableManager; +import net.minecraft.world.storage.loot.ValidationResults; + +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.LootTableProvider}, with a more flexible interface. + */ +public abstract class LootTableProvider implements IDataProvider +{ + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + + private final DataGenerator generator; + + public LootTableProvider( DataGenerator generator ) + { + this.generator = generator; + } + + @Override + public void act( @Nonnull DirectoryCache cache ) + { + + ValidationResults validation = new ValidationResults(); + Map tables = new HashMap<>(); + registerLoot( ( id, table ) -> { + if( tables.containsKey( id ) ) validation.addProblem( "Duplicate loot tables for " + id ); + tables.put( id, table ); + } ); + + tables.forEach( ( key, value ) -> LootTableManager.func_215302_a( validation, key, value, tables::get ) ); + + 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 + { + IDataProvider.save( GSON, cache, LootTableManager.toJson( 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/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java new file mode 100644 index 000000000..f40295ccc --- /dev/null +++ b/src/main/java/dan200/computercraft/data/LootTables.java @@ -0,0 +1,72 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; +import dan200.computercraft.shared.data.PlayerCreativeLootCondition; +import net.minecraft.block.Block; +import net.minecraft.data.DataGenerator; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.*; +import net.minecraft.world.storage.loot.conditions.Alternative; +import net.minecraft.world.storage.loot.conditions.SurvivesExplosion; + +import java.util.function.BiConsumer; + +public class LootTables extends LootTableProvider +{ + public LootTables( DataGenerator generator ) + { + super( generator ); + } + + @Override + protected void registerLoot( BiConsumer add ) + { + basicDrop( add, ComputerCraft.Blocks.diskDrive ); + basicDrop( add, ComputerCraft.Blocks.monitorNormal ); + basicDrop( add, ComputerCraft.Blocks.monitorAdvanced ); + basicDrop( add, ComputerCraft.Blocks.printer ); + basicDrop( add, ComputerCraft.Blocks.speaker ); + basicDrop( add, ComputerCraft.Blocks.wiredModemFull ); + basicDrop( add, ComputerCraft.Blocks.wirelessModemNormal ); + basicDrop( add, ComputerCraft.Blocks.wirelessModemAdvanced ); + + computerDrop( add, ComputerCraft.Blocks.computerNormal ); + computerDrop( add, ComputerCraft.Blocks.computerAdvanced ); + computerDrop( add, ComputerCraft.Blocks.turtleNormal ); + computerDrop( add, ComputerCraft.Blocks.turtleAdvanced ); + } + + private static void basicDrop( BiConsumer add, Block block ) + { + add.accept( block.getRegistryName(), LootTable + .builder() + .addLootPool( LootPool.builder() + .name( "main" ) + .rolls( ConstantRange.of( 1 ) ) + .addEntry( ItemLootEntry.builder( block ) ) + .acceptCondition( SurvivesExplosion.builder() ) + ).build() ); + } + + private static void computerDrop( BiConsumer add, Block block ) + { + add.accept( block.getRegistryName(), LootTable + .builder() + .addLootPool( LootPool.builder() + .name( "main" ) + .rolls( ConstantRange.of( 1 ) ) + .addEntry( DynamicLootEntry.func_216162_a( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) ) + .acceptCondition( Alternative.builder( + BlockNamedEntityLootCondition.builder(), + PlayerCreativeLootCondition.builder().inverted() + ) ) + ).build() ); + } +} 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..9451df12e --- /dev/null +++ b/src/main/java/dan200/computercraft/data/RecipeWrapper.java @@ -0,0 +1,92 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import com.google.gson.JsonObject; +import net.minecraft.data.IFinishedRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; + +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. + */ +public final class RecipeWrapper implements IFinishedRecipe +{ + private final IFinishedRecipe recipe; + private final CompoundNBT resultData; + private final IRecipeSerializer serializer; + + private RecipeWrapper( IFinishedRecipe recipe, CompoundNBT resultData, IRecipeSerializer serializer ) + { + this.resultData = resultData; + this.recipe = recipe; + this.serializer = serializer; + } + + public static Consumer wrap( IRecipeSerializer serializer, Consumer original ) + { + return x -> original.accept( new RecipeWrapper( x, null, serializer ) ); + } + + public static Consumer wrap( IRecipeSerializer serializer, Consumer original, CompoundNBT resultData ) + { + return x -> original.accept( new RecipeWrapper( x, resultData, serializer ) ); + } + + public static Consumer wrap( IRecipeSerializer serializer, Consumer original, Consumer resultData ) + { + CompoundNBT tag = new CompoundNBT(); + resultData.accept( tag ); + return x -> original.accept( new RecipeWrapper( x, tag, serializer ) ); + } + + @Override + public void serialize( @Nonnull JsonObject jsonObject ) + { + recipe.serialize( jsonObject ); + + if( resultData != null ) + { + JsonObject object = JSONUtils.getJsonObject( jsonObject, "result" ); + object.addProperty( "nbt", resultData.toString() ); + } + } + + @Nonnull + @Override + public ResourceLocation getID() + { + return recipe.getID(); + } + + @Nonnull + @Override + public IRecipeSerializer getSerializer() + { + return serializer; + } + + @Nullable + @Override + public JsonObject getAdvancementJson() + { + return recipe.getAdvancementJson(); + } + + @Nullable + @Override + public ResourceLocation getAdvancementID() + { + return recipe.getAdvancementID(); + } +} diff --git a/src/main/java/dan200/computercraft/data/Recipes.java b/src/main/java/dan200/computercraft/data/Recipes.java new file mode 100644 index 000000000..9523d80ac --- /dev/null +++ b/src/main/java/dan200/computercraft/data/Recipes.java @@ -0,0 +1,320 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.data.Tags.CCTags; +import dan200.computercraft.shared.TurtleUpgrades; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; +import dan200.computercraft.shared.turtle.items.TurtleItemFactory; +import dan200.computercraft.shared.util.Colour; +import dan200.computercraft.shared.util.ImpostorRecipe; +import dan200.computercraft.shared.util.ImpostorShapelessRecipe; +import net.minecraft.advancements.criterion.InventoryChangeTrigger; +import net.minecraft.advancements.criterion.ItemPredicate; +import net.minecraft.block.Blocks; +import net.minecraft.data.*; +import net.minecraft.item.*; +import net.minecraft.tags.Tag; +import net.minecraft.util.IItemProvider; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.Tags; + +import javax.annotation.Nonnull; +import java.util.Locale; +import java.util.function.Consumer; + +public class Recipes extends RecipeProvider +{ + public Recipes( DataGenerator generator ) + { + super( generator ); + } + + @Override + protected void registerRecipes( @Nonnull Consumer add ) + { + basicRecipes( add ); + diskColours( add ); + pocketUpgrades( add ); + turtleUpgrades( add ); + } + + /** + * 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 + .shapelessRecipe( ComputerCraft.Items.disk ) + .addIngredient( Tags.Items.DUSTS_REDSTONE ) + .addIngredient( Items.PAPER ) + .addIngredient( DyeItem.getItem( ofColour( colour ) ) ) + .setGroup( "computercraft:disk" ) + .addCriterion( "has_drive", inventoryChange( ComputerCraft.Blocks.diskDrive ) ) + .build( RecipeWrapper.wrap( + ImpostorShapelessRecipe.SERIALIZER, add, + x -> x.putInt( "color", 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 + .shapedRecipe( result.getItem() ) + .setGroup( String.format( "%s:turtle_%s", ComputerCraft.MOD_ID, nameId ) ) + .patternLine( "#T" ) + .key( '#', base.getItem() ) + .key( 'T', upgrade.getCraftingItem().getItem() ) + .addCriterion( "has_items", + inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) ) + .build( + 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 ); + + TurtleUpgrades.getVanillaUpgrades().forEach( upgrade -> { + ItemStack result = PocketComputerItemFactory.create( -1, null, -1, family, null ); + ShapedRecipeBuilder + .shapedRecipe( result.getItem() ) + .setGroup( String.format( "%s:pocket_%s", ComputerCraft.MOD_ID, nameId ) ) + .patternLine( "#" ) + .patternLine( "P" ) + .key( '#', base.getItem() ) + .key( 'P', upgrade.getCraftingItem().getItem() ) + .addCriterion( "has_items", + inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) ) + .build( + 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 + .shapedRecipe( ComputerCraft.Items.cable, 6 ) + .patternLine( " # " ) + .patternLine( "#R#" ) + .patternLine( " # " ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_modem", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.computerNormal ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_redstone", inventoryChange( Tags.Items.DUSTS_REDSTONE ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.computerAdvanced ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_components", inventoryChange( Items.REDSTONE, Items.GOLD_INGOT ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.computerCommand ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'R', Blocks.COMMAND_BLOCK ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_components", inventoryChange( Blocks.COMMAND_BLOCK ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.diskDrive ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#R#" ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.monitorNormal ) + .patternLine( "###" ) + .patternLine( "#G#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.STONE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.monitorAdvanced, 4 ) + .patternLine( "###" ) + .patternLine( "#G#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Items.pocketComputerNormal ) + .patternLine( "###" ) + .patternLine( "#A#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.STONE ) + .key( 'A', Items.GOLDEN_APPLE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Items.pocketComputerAdvanced ) + .patternLine( "###" ) + .patternLine( "#A#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'A', Items.GOLDEN_APPLE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.printer ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#D#" ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .key( 'D', Tags.Items.DYES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.speaker ) + .patternLine( "###" ) + .patternLine( "#N#" ) + .patternLine( "#R#" ) + .key( '#', Tags.Items.STONE ) + .key( 'N', Blocks.NOTE_BLOCK ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Items.wiredModem ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_cable", inventoryChange( ComputerCraft.Items.cable ) ) + .build( add ); + + ShapelessRecipeBuilder + .shapelessRecipe( ComputerCraft.Blocks.wiredModemFull ) + .addIngredient( ComputerCraft.Items.wiredModem ) + .addCriterion( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) ) + .build( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_from" ) ); + ShapelessRecipeBuilder + .shapelessRecipe( ComputerCraft.Items.wiredModem ) + .addIngredient( ComputerCraft.Blocks.wiredModemFull ) + .addCriterion( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) ) + .build( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_to" ) ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.wirelessModemNormal ) + .patternLine( "###" ) + .patternLine( "#E#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.STONE ) + .key( 'E', Tags.Items.ENDER_PEARLS ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.wirelessModemAdvanced ) + .patternLine( "###" ) + .patternLine( "#E#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'E', Items.ENDER_EYE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_wireless", inventoryChange( ComputerCraft.Blocks.wirelessModemNormal ) ) + .build( add ); + } + + private static DyeColor ofColour( Colour colour ) + { + return DyeColor.byId( 15 - colour.ordinal() ); + } + + private static InventoryChangeTrigger.Instance inventoryChange( Tag stack ) + { + return InventoryChangeTrigger.Instance.forItems( ItemPredicate.Builder.create().tag( stack ).build() ); + } + + private static InventoryChangeTrigger.Instance inventoryChange( IItemProvider... stack ) + { + return InventoryChangeTrigger.Instance.forItems( stack ); + } +} diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java new file mode 100644 index 000000000..bc78e3e7b --- /dev/null +++ b/src/main/java/dan200/computercraft/data/Tags.java @@ -0,0 +1,52 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import dan200.computercraft.ComputerCraft; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.ItemTagsProvider; +import net.minecraft.item.Item; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.Tag; +import net.minecraft.util.ResourceLocation; + +import static dan200.computercraft.data.Tags.CCTags.*; + +public class Tags extends ItemTagsProvider +{ + public static class CCTags + { + public static final Tag COMPUTER = item( "computer" ); + public static final Tag TURTLE = item( "turtle" ); + public static final Tag WIRED_MODEM = item( "wired_modem" ); + public static final Tag MONITOR = item( "monitor" ); + } + + public Tags( DataGenerator generator ) + { + super( generator ); + } + + @Override + protected void registerTags() + { + getBuilder( COMPUTER ) + .add( ComputerCraft.Items.computerNormal ) + .add( ComputerCraft.Items.computerAdvanced ) + .add( ComputerCraft.Items.computerCommand ); + getBuilder( TURTLE ).add( ComputerCraft.Items.turtleNormal, ComputerCraft.Items.turtleAdvanced ); + getBuilder( WIRED_MODEM ).add( ComputerCraft.Items.wiredModem, ComputerCraft.Blocks.wiredModemFull.asItem() ); + getBuilder( MONITOR ) + .add( ComputerCraft.Blocks.monitorNormal.asItem() ) + .add( ComputerCraft.Blocks.monitorAdvanced.asItem() ); + } + + private static Tag item( String name ) + { + return new ItemTags.Wrapper( new ResourceLocation( ComputerCraft.MOD_ID, name ) ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 017725408..652d7608a 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -38,42 +38,42 @@ public final class Config private static final String TRANSLATION_PREFIX = "gui.computercraft.config."; - private static ConfigValue computerSpaceLimit; - private static ConfigValue floppySpaceLimit; - private static ConfigValue maximumFilesOpen; - private static ConfigValue disableLua51Features; - private static ConfigValue defaultComputerSettings; - private static ConfigValue debugEnabled; - private static ConfigValue logComputerErrors; + private static final ConfigValue computerSpaceLimit; + private static final ConfigValue floppySpaceLimit; + private static final ConfigValue maximumFilesOpen; + private static final ConfigValue disableLua51Features; + private static final ConfigValue defaultComputerSettings; + private static final ConfigValue debugEnabled; + private static final ConfigValue logComputerErrors; - private static ConfigValue computerThreads; - private static ConfigValue maxMainGlobalTime; - private static ConfigValue maxMainComputerTime; + private static final ConfigValue computerThreads; + private static final ConfigValue maxMainGlobalTime; + private static final ConfigValue maxMainComputerTime; - private static ConfigValue httpEnabled; - private static ConfigValue httpWebsocketEnabled; - private static ConfigValue> httpRules; + private static final ConfigValue httpEnabled; + private static final ConfigValue httpWebsocketEnabled; + private static final ConfigValue> httpRules; - private static ConfigValue httpTimeout; - private static ConfigValue httpMaxRequests; - private static ConfigValue httpMaxDownload; - private static ConfigValue httpMaxUpload; - private static ConfigValue httpMaxWebsockets; - private static ConfigValue httpMaxWebsocketMessage; + private static final ConfigValue httpTimeout; + private static final ConfigValue httpMaxRequests; + private static final ConfigValue httpMaxDownload; + private static final ConfigValue httpMaxUpload; + private static final ConfigValue httpMaxWebsockets; + private static final ConfigValue httpMaxWebsocketMessage; - private static ConfigValue commandBlockEnabled; - private static ConfigValue modemRange; - private static ConfigValue modemHighAltitudeRange; - private static ConfigValue modemRangeDuringStorm; - private static ConfigValue modemHighAltitudeRangeDuringStorm; - private static ConfigValue maxNotesPerTick; + private static final ConfigValue commandBlockEnabled; + private static final ConfigValue modemRange; + private static final ConfigValue modemHighAltitudeRange; + private static final ConfigValue modemRangeDuringStorm; + private static final ConfigValue modemHighAltitudeRangeDuringStorm; + private static final ConfigValue maxNotesPerTick; - private static ConfigValue turtlesNeedFuel; - private static ConfigValue turtleFuelLimit; - private static ConfigValue advancedTurtleFuelLimit; - private static ConfigValue turtlesObeyBlockProtection; - private static ConfigValue turtlesCanPush; - private static ConfigValue> turtleDisabledActions; + private static final ConfigValue turtlesNeedFuel; + private static final ConfigValue turtleFuelLimit; + private static final ConfigValue advancedTurtleFuelLimit; + private static final ConfigValue turtlesObeyBlockProtection; + private static final ConfigValue turtlesCanPush; + private static final ConfigValue> turtleDisabledActions; private static final ForgeConfigSpec spec; diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java index c2842ff28..898c321ce 100644 --- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java @@ -40,4 +40,9 @@ public Set> getRequiredParameters() { return Collections.singleton( LootParameters.BLOCK_ENTITY ); } + + public static IBuilder builder() + { + return () -> INSTANCE; + } } diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java index 9055f3c17..6a91f90fe 100644 --- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -40,4 +40,9 @@ public Set> getRequiredParameters() { return Collections.singleton( LootParameters.THIS_ENTITY ); } + + public static IBuilder builder() + { + return () -> INSTANCE; + } } 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 508109f2d..a527a5ecb 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -16,7 +16,7 @@ import java.util.Iterator; import java.util.Set; -public class ClientMonitor extends ClientTerminal +public final class ClientMonitor extends ClientTerminal { private static final Set allMonitors = new HashSet<>(); @@ -24,7 +24,8 @@ public class ClientMonitor extends ClientTerminal public long lastRenderFrame = -1; public BlockPos lastRenderPos = null; - public VertexBuffer buffer = null; + + public VertexBuffer buffer; public ClientMonitor( boolean colour, TileMonitor origin ) { @@ -37,16 +38,45 @@ public TileMonitor getOrigin() return origin; } + /** + * Create the appropriate buffer if needed. + * + * @param renderer The renderer to use. This can be fetched from {@link MonitorRenderer#current()}. + * @return If a buffer was created. This will return {@code false} if we already have an appropriate buffer, + * or this mode does not require one. + */ @OnlyIn( Dist.CLIENT ) - public void createBuffer() + public boolean createBuffer( MonitorRenderer renderer ) { - if( buffer == null ) + switch( renderer ) { - buffer = new VertexBuffer( FixedWidthFontRenderer.TYPE.getVertexFormat() ); - synchronized( allMonitors ) - { - allMonitors.add( this ); - } + case VBO: + if( buffer != null ) return false; + + deleteBuffers(); + buffer = new VertexBuffer( FixedWidthFontRenderer.POSITION_COLOR_TEX ); + addMonitor(); + return true; + + default: + return false; + } + } + + private void addMonitor() + { + synchronized( allMonitors ) + { + allMonitors.add( this ); + } + } + + private void deleteBuffers() + { + if( buffer != null ) + { + buffer.close(); + buffer = null; } } @@ -60,8 +90,7 @@ public void destroy() allMonitors.remove( this ); } - buffer.close(); - buffer = null; + deleteBuffers(); } } @@ -73,11 +102,7 @@ public static void destroyAll() for( Iterator iterator = allMonitors.iterator(); iterator.hasNext(); ) { ClientMonitor monitor = iterator.next(); - if( monitor.buffer != null ) - { - monitor.buffer.close(); - monitor.buffer = null; - } + monitor.deleteBuffers(); iterator.remove(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java new file mode 100644 index 000000000..4f8bb353a --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java @@ -0,0 +1,98 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.monitor; + +import com.mojang.blaze3d.platform.GLX; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.render.TileEntityMonitorRenderer; + +import javax.annotation.Nonnull; +import java.util.Locale; + +/** + * The render type to use for monitors. + * + * @see TileEntityMonitorRenderer + * @see ClientMonitor + */ +public enum MonitorRenderer +{ + /** + * Determine the best monitor backend. + */ + BEST, + + /** + * Render using VBOs. + * + * @see net.minecraft.client.renderer.vertex.VertexBuffer + */ + VBO; + + private static final MonitorRenderer[] VALUES = values(); + public static final String[] NAMES; + + private final String displayName = "gui.computercraft:config.peripheral.monitor_renderer." + name().toLowerCase( Locale.ROOT ); + + static + { + NAMES = new String[VALUES.length]; + for( int i = 0; i < VALUES.length; i++ ) NAMES[i] = VALUES[i].displayName(); + } + + public String displayName() + { + return displayName; + } + + @Nonnull + public static MonitorRenderer ofString( String name ) + { + for( MonitorRenderer backend : VALUES ) + { + if( backend.displayName.equalsIgnoreCase( name ) || backend.name().equalsIgnoreCase( name ) ) + { + return backend; + } + } + + ComputerCraft.log.warn( "Unknown monitor renderer {}. Falling back to default.", name ); + return BEST; + } + + /** + * Get the current renderer to use. + * + * @return The current renderer. Will not return {@link MonitorRenderer#BEST}. + */ + @Nonnull + public static MonitorRenderer current() + { + MonitorRenderer current = ComputerCraft.monitorRenderer; + switch( current ) + { + case BEST: + return best(); + case VBO: + if( !GLX.useVbo() ) + { + ComputerCraft.log.warn( "VBOs are not supported on your graphics card. Falling back to default." ); + ComputerCraft.monitorRenderer = BEST; + return best(); + } + + return VBO; + default: + return current; + } + } + + private static MonitorRenderer best() + { + return VBO; + } +} diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 8f5c8536d..27a45a406 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -45,14 +45,20 @@ public final class ComputerCraftProxyCommon { @SubscribeEvent + @SuppressWarnings( "deprecation" ) public static void init( FMLCommonSetupEvent event ) { NetworkHandler.setup(); - registerProviders(); - - ArgumentSerializers.register(); + net.minecraftforge.fml.DeferredWorkQueue.runLater( () -> { + registerProviders(); + ArgumentSerializers.register(); + registerLoot(); + } ); + } + public static void registerLoot() + { LootConditionManager.registerCondition( ConstantLootConditionSerializer.of( new ResourceLocation( ComputerCraft.MOD_ID, "block_named" ), BlockNamedEntityLootCondition.class, diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index a4faffdd0..2758a6d11 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -48,13 +48,13 @@ public void resetColour( int i ) { if( i >= 0 && i < colours.length ) { - setColour( i, Colour.values()[i] ); + setColour( i, Colour.VALUES[i] ); } } public void resetColours() { - for( int i = 0; i < Colour.values().length; i++ ) + for( int i = 0; i < Colour.VALUES.length; i++ ) { resetColour( i ); } diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index 32c710dcf..dbd74cd06 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -7,7 +7,6 @@ import com.google.common.base.Predicate; import com.google.common.collect.MapMaker; -import net.minecraft.block.BlockState; import net.minecraft.entity.*; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; @@ -54,8 +53,7 @@ public EntitySize getSize( Pose pose ) public static boolean isLiquidBlock( World world, BlockPos pos ) { if( !World.isValid( pos ) ) return false; - BlockState state = world.getBlockState( pos ); - return !state.getFluidState().isEmpty(); + return world.getBlockState( pos ).getMaterial().isLiquid(); } public static boolean isVecInside( VoxelShape shape, Vec3d vec ) diff --git a/src/main/resources/assets/computercraft/lang/da_dk.lang b/src/main/resources/assets/computercraft/lang/da_dk.lang new file mode 100644 index 000000000..3da64d2a4 --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/da_dk.lang @@ -0,0 +1,48 @@ +tile.computercraft:computer.name=Computer +tile.computercraft:advanced_computer.name=Avanceret Computer +tile.computercraft:drive.name=Diskdrev +tile.computercraft:printer.name=Printer +tile.computercraft:monitor.name=Skærm +tile.computercraft:advanced_monitor.name=Avanceret Skærm +tile.computercraft:wireless_modem.name=Trådløst Modem +tile.computercraft:wired_modem.name=Kablet Modem +tile.computercraft:cable.name=Netværkskabel +tile.computercraft:command_computer.name=Kommandocomputer +tile.computercraft:advanced_modem.name=Endermodem +tile.computercraft:speaker.name=Højttaler + +tile.computercraft:turtle.name=Turtle +tile.computercraft:turtle.upgraded.name=%s Turtle +tile.computercraft:turtle.upgraded_twice.name=%s %s Turtle +tile.computercraft:advanced_turtle.name=Avanceret Turtle +tile.computercraft:advanced_turtle.upgraded.name=Avanceret %s Turtle +tile.computercraft:advanced_turtle.upgraded_twice.name=Avanceret %s %s Turtle + +item.computercraft:disk.name=Floppydisk +item.computercraft:treasure_disk.name=Floppydisk +item.computercraft:page.name=Printet Side +item.computercraft:pages.name=Printede Sider +item.computercraft:book.name=Printet Bog + +item.computercraft:pocket_computer.name=Lommecomputer +item.computercraft:pocket_computer.upgraded.name=%s Lommecomputer +item.computercraft:advanced_pocket_computer.name=Avanceret Lommecomputer +item.computercraft:advanced_pocket_computer.upgraded.name=Avanceret %s Lommecomputer + +upgrade.minecraft:diamond_sword.adjective=Kæmpende +upgrade.minecraft:diamond_shovel.adjective=Gravende +upgrade.minecraft:diamond_pickaxe.adjective=Brydende +upgrade.minecraft:diamond_axe.adjective=Fældende +upgrade.minecraft:diamond_hoe.adjective=Dyrkende +upgrade.computercraft:wireless_modem.adjective=Trådløs +upgrade.minecraft:crafting_table.adjective=Fremstillende +upgrade.computercraft:advanced_modem.adjective=Endertrådløs +upgrade.computercraft:speaker.adjective=Larmende + +chat.computercraft.wired_modem.peripheral_connected=Perifer enhed "%s" koblet til netværk +chat.computercraft.wired_modem.peripheral_disconnected=Perifer enhed "%s" koblet fra netværk + +# Misc tooltips +gui.computercraft.tooltip.copy=Kopier til udklipsholder +gui.computercraft.tooltip.computer_id=(Computer-ID: %s) +gui.computercraft.tooltip.disk_id=(Disk-ID: %s) diff --git a/src/main/resources/assets/computercraft/lang/ko_kr.lang b/src/main/resources/assets/computercraft/lang/ko_kr.lang new file mode 100644 index 000000000..784bb4b31 --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/ko_kr.lang @@ -0,0 +1,195 @@ +itemGroup.computercraft=컴퓨터크래프트 + +tile.computercraft:computer.name=컴퓨터 +tile.computercraft:advanced_computer.name=고급 컴퓨터 +tile.computercraft:drive.name=디스크 드라이브 +tile.computercraft:printer.name=프린터 +tile.computercraft:monitor.name=모니터 +tile.computercraft:advanced_monitor.name=고급 모니터 +tile.computercraft:wireless_modem.name=무선 모뎀 +tile.computercraft:wired_modem.name=유선 모뎀 +tile.computercraft:cable.name=네트워크 케이블 +tile.computercraft:command_computer.name=명령 컴퓨터 +tile.computercraft:advanced_modem.name=엔더 모뎀 +tile.computercraft:speaker.name=스피커 + +tile.computercraft:turtle.name=터틀 +tile.computercraft:turtle.upgraded.name=%s 터틀 +tile.computercraft:turtle.upgraded_twice.name=%s %s 터틀 +tile.computercraft:advanced_turtle.name=고급 터틀 +tile.computercraft:advanced_turtle.upgraded.name=고급 %s 터틀 +tile.computercraft:advanced_turtle.upgraded_twice.name=고급 %s %s 터틀 + +item.computercraft:disk.name=플로피 디스크 +item.computercraft:treasure_disk.name=플로피 디스크 +item.computercraft:page.name=인쇄된 페이지 +item.computercraft:pages.name=인쇄된 페이지 모음 +item.computercraft:book.name=인쇄된 책 + +item.computercraft:pocket_computer.name=포켓 컴퓨터 +item.computercraft:pocket_computer.upgraded.name=%s 포켓 컴퓨터 +item.computercraft:advanced_pocket_computer.name=고급 포켓 컴퓨터 +item.computercraft:advanced_pocket_computer.upgraded.name=고급 %s 포켓 컴퓨터 + +upgrade.minecraft:diamond_sword.adjective=난투 +upgrade.minecraft:diamond_shovel.adjective=굴착 +upgrade.minecraft:diamond_pickaxe.adjective=채굴 +upgrade.minecraft:diamond_axe.adjective=벌목 +upgrade.minecraft:diamond_hoe.adjective=농업 +upgrade.computercraft:wireless_modem.adjective=무선 +upgrade.minecraft:crafting_table.adjective=조합 +upgrade.computercraft:advanced_modem.adjective=엔더 +upgrade.computercraft:speaker.adjective=소음 + +chat.computercraft.wired_modem.peripheral_connected=주변 "%s"이 네트워크에 연결되었습니다. +chat.computercraft.wired_modem.peripheral_disconnected=주변 "%s"이 네트워크로부터 분리되었습니다. + +# Command descriptions, usage and any additional messages. +commands.computercraft.synopsis=컴퓨터를 제어하기 위한 다양한 명령어 +commands.computercraft.desc=/computercraft 명령어는 컴퓨터를 제어하고 상호작용하기 위한 다양한 디버깅 및 관리자 도구를 제공합니다. + +commands.computercraft.help.synopsis=특정 명령어에 대한 도움말을 제공하기 +commands.computercraft.help.desc= +commands.computercraft.help.usage=[command] +commands.computercraft.help.no_children=%s에는 하위 명령어가 없습니다. +commands.computercraft.help.no_command='%s'라는 명령어가 없습니다. + +commands.computercraft.dump.synopsis=컴퓨터의 상태를 보여주기 +commands.computercraft.dump.desc=모든 시스템의 상태 또는 한 시스템에 대한 특정 정보를 표시합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: "@My Computer")을 지정할 수 있습니다. +commands.computercraft.dump.usage=[id] +commands.computercraft.dump.action=이 컴퓨터에 대한 추가 정보를 봅니다. + +commands.computercraft.shutdown.synopsis=시스템을 원격으로 종료하기 +commands.computercraft.shutdown.desc=나열된 시스템 또는 지정된 시스템이 없는 경우 모두 종료합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: "@My Computer")을 지정할 수 있습니다. +commands.computercraft.shutdown.usage=[ids...] +commands.computercraft.shutdown.done=%s/%s 컴퓨터 시스템 종료 + +commands.computercraft.turn_on.synopsis=시스템을 원격으로 실행하기 +commands.computercraft.turn_on.desc=나열된 컴퓨터를 실행합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: "@My Computer")을 지정할 수 있습니다. +commands.computercraft.turn_on.usage=[ids...] +commands.computercraft.turn_on.done=%s/%s 컴퓨터 시스템 실행 + +commands.computercraft.tp.synopsis=특정 컴퓨터로 순간이동하기 +commands.computercraft.tp.desc=컴퓨터의 위치로 순간이동합니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다. +commands.computercraft.tp.usage= +commands.computercraft.tp.action=이 컴퓨터로 순간이동하기 +commands.computercraft.tp.not_entity=비플레이어한테 터미널을 열 수 없습니다. +commands.computercraft.tp.not_there=월드에서 컴퓨터를 위치시킬 수 없습니다. + +commands.computercraft.view.synopsis=컴퓨터의 터미널을 보기 +commands.computercraft.view.desc=컴퓨터의 원격 제어를 허용하는 컴퓨터의 터미널을 엽니다. 이것은 터틀의 인벤토리에 대한 접근을 제공하지 않습니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다. +commands.computercraft.view.usage= +commands.computercraft.view.action=이 컴퓨터를 봅니다. +commands.computercraft.view.not_player=비플레이어한테 터미널을 열 수 없습니다. + +commands.computercraft.track.synopsis=컴퓨터의 실행 시간을 추적하기 +commands.computercraft.track.desc=컴퓨터가 실행되는 기간과 처리되는 이벤트 수를 추적합니다. 이는 /forge 트랙과 유사한 방법으로 정보를 제공하며 지연 로그에 유용할 수 있습니다. + +commands.computercraft.track.start.synopsis=모든 컴퓨터의 추적을 시작하기 +commands.computercraft.track.start.desc=모든 컴퓨터의 이벤트 및 실행 시간 추적을 시작합니다. 이는 이전 실행의 결과를 폐기할 것입니다. +commands.computercraft.track.start.usage= +commands.computercraft.track.start.stop=%s을(를) 실행하여 추적을 중지하고 결과를 확인합니다. + +commands.computercraft.track.stop.synopsis=모든 컴퓨터의 추적을 중지하기 +commands.computercraft.track.stop.desc=모든 컴퓨터의 이벤트 및 실행 시간 추적을 중지합니다. +commands.computercraft.track.stop.usage= +commands.computercraft.track.stop.action=추적을 중지하려면 클릭하세요. +commands.computercraft.track.stop.not_enabled=현재 추적하는 컴퓨터가 없습니다. + +commands.computercraft.track.dump.synopsis=최신 추적 결과를 덤프하기 +commands.computercraft.track.dump.desc=최신 컴퓨터 추적의 결과를 덤프합니다. +commands.computercraft.track.dump.usage=[kind] +commands.computercraft.track.dump.no_timings=사용가능한 시간이 없습니다. +commands.computercraft.track.dump.no_field=알 수 없는 필드 '%s' +commands.computercraft.track.dump.computer=컴퓨터 + +commands.computercraft.reload.synopsis=컴퓨터크래프트 구성파일을 리로드하기 +commands.computercraft.reload.desc=컴퓨터크래프트 구성파일을 리로드합니다. +commands.computercraft.reload.usage= +commands.computercraft.reload.done=리로드된 구성 + +commands.computercraft.queue.synopsis=computer_command 이벤트를 명령 컴퓨터에 보내기 +commands.computercraft.queue.desc=computer_command 이벤트를 명령 컴퓨터로 전송하여 추가 인수를 전달합니다. 이는 대부분 지도 제작자를 위해 설계되었으며, 보다 컴퓨터 친화적인 버전의 /trigger 역할을 합니다. 어떤 플레이어든 명령을 실행할 수 있으며, 이는 텍스트 구성 요소의 클릭 이벤트를 통해 수행될 가능성이 가장 높습니다. +commands.computercraft.queue.usage= [args...] + +commands.computercraft.generic.no_position= +commands.computercraft.generic.position=%s, %s, %s +commands.computercraft.generic.yes=Y +commands.computercraft.generic.no=N +commands.computercraft.generic.exception=처리되지 않은 예외 (%s) +commands.computercraft.generic.additional_rows=%d개의 추가 행... + +commands.computercraft.argument.no_matching='%s'와 일치하는 컴퓨터가 없습니다. +commands.computercraft.argument.many_matching='%s'와 일치하는 여러 컴퓨터 (인스턴스 %s) +commands.computercraft.argument.not_number='%s'는 숫자가 아닙니다. + +# Names for the various tracking fields. +tracking_field.computercraft.tasks.name=작업 +tracking_field.computercraft.total.name=전체 시간 +tracking_field.computercraft.average.name=평균 시간 +tracking_field.computercraft.max.name=최대 시간 + +tracking_field.computercraft.server_count.name=서버 작업 수 +tracking_field.computercraft.server_time.name=서버 작업 시간 + +tracking_field.computercraft.peripheral.name=주변 호출 +tracking_field.computercraft.fs.name=파일시스템 작업 +tracking_field.computercraft.turtle.name=터틀 작업 + +tracking_field.computercraft.http.name=HTTP 요청 +tracking_field.computercraft.http_upload.name=HTTP 업로드 +tracking_field.computercraft.http_download.name=HTTT 다운로드 + +tracking_field.computercraft.websocket_incoming.name=웹소켓 수신 +tracking_field.computercraft.websocket_outgoing.name=웹소켓 송신 + +tracking_field.computercraft.coroutines_created.name=코루틴 생성됨 +tracking_field.computercraft.coroutines_dead.name=코루틴 처리됨 + +# Misc tooltips +gui.computercraft.tooltip.copy=클립보드에 복사 +gui.computercraft.tooltip.computer_id=(컴퓨터 ID: %s) +gui.computercraft.tooltip.disk_id=(디스크 ID: %s) + +# Config options +gui.computercraft:config.computer_space_limit=컴퓨터 공간 제한 (바이트) +gui.computercraft:config.floppy_space_limit=플로피 디스크 공간 제한 (바이트) +gui.computercraft:config.maximum_open_files=컴퓨터당 최대 파일 열기 +gui.computercraft:config.disable_lua51_features=Lua 5.1 기능 미사용 +gui.computercraft:config.default_computer_settings=기본 컴퓨터 설정 +gui.computercraft:config.debug_enabled=디버그 라이브러리 사용 +gui.computercraft:config.log_computer_errors=컴퓨터 오류 로그 + +gui.computercraft:config.execution=실행 +gui.computercraft:config.execution.computer_threads=컴퓨터 쓰레드 +gui.computercraft:config.execution.max_main_global_time=전역 시간 당 서버 제한 +gui.computercraft:config.execution.max_main_computer_time=컴퓨터 시간 당 서버 제한 + +gui.computercraft:config.http=HTTP +gui.computercraft:config.http.enabled=HTTP API 사용하기 +gui.computercraft:config.http.websocket_enabled=웹소켓 사용 +gui.computercraft:config.http.allowed_domains=허용된 도메인 +gui.computercraft:config.http.blocked_domains=차단된 도메인 + +gui.computercraft:config.http.timeout=타임아웃 +gui.computercraft:config.http.max_requests=최대 동시 요청 수 +gui.computercraft:config.http.max_download=최대 응답 크기 +gui.computercraft:config.http.max_upload=최대 요청 크기 +gui.computercraft:config.http.max_websockets=최대 동시 웹소켓 수 +gui.computercraft:config.http.max_websocket_message=최대 웹 포켓 메시지 크기 + +gui.computercraft:config.peripheral=주변 +gui.computercraft:config.peripheral.command_block_enabled=명령 블록 주변 장치 사용 +gui.computercraft:config.peripheral.modem_range=모뎀 범위(기본값) +gui.computercraft:config.peripheral.modem_high_altitude_range=모뎀 범위(높은 고도) +gui.computercraft:config.peripheral.modem_range_during_storm=모뎀 범위(나쁜 날씨) +gui.computercraft:config.peripheral.modem_high_altitude_range_during_storm=모뎀 범위(높은 고도, 나쁜 날씨) +gui.computercraft:config.peripheral.max_notes_per_tick=컴퓨터가 한 번에 재생할 수 있는 최대 소리 수 + +gui.computercraft:config.turtle=터틀 +gui.computercraft:config.turtle.need_fuel=연료 사용 +gui.computercraft:config.turtle.normal_fuel_limit=터틀 연료 제한 +gui.computercraft:config.turtle.advanced_fuel_limit=고급 터틀 연료 제한 +gui.computercraft:config.turtle.obey_block_protection=터틀이 블록 보호에 따르기 +gui.computercraft:config.turtle.can_push=터틀이 엔티티 밀어내기 +gui.computercraft:config.turtle.disabled_actions=터틀 액션 미사용 diff --git a/src/main/resources/assets/computercraft/models/block/modem.json b/src/main/resources/assets/computercraft/models/block/modem.json index fd6ff916e..7ea4efaef 100644 --- a/src/main/resources/assets/computercraft/models/block/modem.json +++ b/src/main/resources/assets/computercraft/models/block/modem.json @@ -10,7 +10,7 @@ "faces": { "down": { "uv": [ 2, 13, 14, 16 ], "texture": "#front" }, "up": { "uv": [ 2, 0, 14, 3 ], "texture": "#front" }, - "north": { "uv": [ 2, 2, 14, 14 ], "texture": "#back" }, + "north": { "uv": [ 2, 2, 14, 14 ], "texture": "#back", "cullface": "north" }, "south": { "uv": [ 2, 2, 14, 14 ], "texture": "#front" }, "west": { "uv": [ 0, 2, 3, 14 ], "texture": "#front" }, "east": { "uv": [ 13, 2, 16, 14 ], "texture": "#front" } diff --git a/src/main/resources/assets/computercraft/models/block/turtle_base.json b/src/main/resources/assets/computercraft/models/block/turtle_base.json index a4788803d..aa3e71418 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_base.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_base.json @@ -8,23 +8,23 @@ "from": [ 2, 2, 2 ], "to": [ 14, 14, 13 ], "faces": { - "down": { "uv": [ 2.75, 0, 5.75, 2.75 ], "texture": "#texture" }, - "up": { "uv": [ 5.75, 0, 8.75, 2.75 ], "texture": "#texture" }, - "north": { "uv": [ 8.5, 5.75, 11.5, 2.75 ], "texture": "#texture" }, - "south": { "uv": [ 2.75, 5.75, 5.75, 2.75 ], "texture": "#texture" }, - "west": { "uv": [ 0, 5.75, 2.75, 2.75 ], "texture": "#texture" }, - "east": { "uv": [ 5.75, 5.75, 8.5, 2.75 ], "texture": "#texture" } + "down": { "uv": [ 5.75, 2.75, 2.75, 0 ], "texture": "#texture" }, + "up": { "uv": [ 8.75, 0, 5.75, 2.75 ], "texture": "#texture" }, + "north": { "uv": [ 11.5, 5.75, 8.5, 2.75 ], "texture": "#texture" }, + "south": { "uv": [ 5.75, 5.75, 2.75, 2.75 ], "texture": "#texture" }, + "west": { "uv": [ 8.5, 5.75, 5.75, 2.75 ], "texture": "#texture" }, + "east": { "uv": [ 2.75, 5.75, 0, 2.75 ], "texture": "#texture" } } }, { "from": [ 3, 6, 13 ], "to": [ 13, 13, 15 ], "faces": { - "down": { "uv": [ 9.25, 0, 11.75, 0.5 ], "texture": "#texture" }, - "up": { "uv": [ 11.75, 0, 14.25, 0.5 ], "texture": "#texture" }, - "south": { "uv": [ 9.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, - "west": { "uv": [ 8.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, - "east": { "uv": [ 11.75, 2.25, 12.25, 0.5 ], "texture": "#texture" } + "down": { "uv": [ 11.75, 0.5, 9.25, 0 ], "texture": "#texture" }, + "up": { "uv": [ 14.25, 0, 11.75, 0.5 ], "texture": "#texture" }, + "south": { "uv": [ 11.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, + "west": { "uv": [ 12.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, + "east": { "uv": [ 9.25, 2.25, 8.75, 0.5 ], "texture": "#texture" } } } ] diff --git a/src/main/resources/assets/computercraft/models/block/turtle_colour.json b/src/main/resources/assets/computercraft/models/block/turtle_colour.json index 6e5515574..d40487d67 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_colour.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_colour.json @@ -8,46 +8,46 @@ "from": [ 2, 2, 2 ], "to": [ 14, 14, 13 ], "faces": { - "down": { "uv": [ 2.75, 5.75, 5.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "up": { "uv": [ 5.75, 5.75, 8.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "north": { "uv": [ 8.5, 11.5, 11.5, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "south": { "uv": [ 2.75, 11.5, 5.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "west": { "uv": [ 0, 11.5, 2.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "east": { "uv": [ 5.75, 11.5, 8.5, 8.555 ], "texture": "#texture", "tintindex": 0 } + "down": { "uv": [ 5.75, 8.5, 2.75, 5.75 ], "texture": "#texture", "tintindex": 0 }, + "up": { "uv": [ 8.75, 5.75, 5.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, + "north": { "uv": [ 11.5, 11.5, 8.5, 8.5 ], "texture": "#texture", "tintindex": 0 }, + "south": { "uv": [ 5.75, 11.5, 2.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, + "west": { "uv": [ 8.5, 11.5, 5.75, 8.555 ], "texture": "#texture", "tintindex": 0 }, + "east": { "uv": [ 2.75, 11.5, 0, 8.5 ], "texture": "#texture", "tintindex": 0 } } }, { "from": [ 3, 6, 13 ], "to": [ 13, 13, 15 ], "faces": { - "down": { "uv": [ 9.25, 5.75, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, - "up": { "uv": [ 11.75, 5.75, 14.25, 6.25 ], "texture": "#texture", "tintindex": 0 }, - "south": { "uv": [ 9.25, 8, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, - "west": { "uv": [ 8.75, 8, 9.25, 6.25 ], "texture": "#texture", "tintindex": 0 }, - "east": { "uv": [ 11.75, 8, 12.25, 6.25 ], "texture": "#texture", "tintindex": 0 } + "down": { "uv": [ 11.75, 6.25, 9.25, 5.75 ], "texture": "#texture", "tintindex": 0 }, + "up": { "uv": [ 14.25, 5.75, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, + "south": { "uv": [ 11.75, 8, 9.25, 6.25 ], "texture": "#texture", "tintindex": 0 }, + "west": { "uv": [ 12.25, 8, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, + "east": { "uv": [ 9.25, 8, 8.75, 6.25 ], "texture": "#texture", "tintindex": 0 } } }, { "from": [ 2, 2, 2 ], "to": [ 14, 14, 13 ], "faces": { - "down": { "uv": [ 2.75, 0, 5.75, 2.75 ], "texture": "#texture" }, - "up": { "uv": [ 5.75, 0, 8.75, 2.75 ], "texture": "#texture" }, - "north": { "uv": [ 8.5, 5.75, 11.5, 2.75 ], "texture": "#texture" }, - "south": { "uv": [ 2.75, 5.75, 5.75, 2.75 ], "texture": "#texture" }, - "west": { "uv": [ 0, 5.75, 2.75, 2.75 ], "texture": "#texture" }, - "east": { "uv": [ 5.75, 5.75, 8.5, 2.75 ], "texture": "#texture" } + "down": { "uv": [ 5.75, 2.75, 2.75, 0 ], "texture": "#texture" }, + "up": { "uv": [ 8.75, 0, 5.75, 2.75 ], "texture": "#texture" }, + "north": { "uv": [ 11.5, 5.75, 8.5, 2.75 ], "texture": "#texture" }, + "south": { "uv": [ 5.75, 5.75, 2.75, 2.75 ], "texture": "#texture" }, + "west": { "uv": [ 8.5, 5.75, 5.75, 2.75 ], "texture": "#texture" }, + "east": { "uv": [ 2.75, 5.75, 0, 2.75 ], "texture": "#texture" } } }, { "from": [ 3, 6, 13 ], "to": [ 13, 13, 15 ], "faces": { - "down": { "uv": [ 9.25, 0, 11.75, 0.5 ], "texture": "#texture" }, - "up": { "uv": [ 11.75, 0, 14.25, 0.5 ], "texture": "#texture" }, - "south": { "uv": [ 9.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, - "west": { "uv": [ 8.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, - "east": { "uv": [ 11.75, 2.25, 12.25, 0.5 ], "texture": "#texture" } + "down": { "uv": [ 11.75, 0.5, 9.25, 0 ], "texture": "#texture" }, + "up": { "uv": [ 14.25, 0, 11.75, 0.5 ], "texture": "#texture" }, + "south": { "uv": [ 11.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, + "west": { "uv": [ 12.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, + "east": { "uv": [ 9.25, 2.25, 8.75, 0.5 ], "texture": "#texture" } } } ] diff --git a/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_left.json b/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_left.json index 1dcf2e72a..823c5e590 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_left.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_left.json @@ -8,8 +8,8 @@ "from": [ 0.5, 4.5, 3.5 ], "to": [ 2, 12.5, 11.5 ], "faces": { - "down": { "uv": [ 13, 2, 16, 14 ], "texture": "#texture" }, - "up": { "uv": [ 13, 2, 16, 14 ], "texture": "#texture" }, + "down": { "uv": [ 2, 14, 14, 16 ], "texture": "#texture", "rotation": 270 }, + "up": { "uv": [ 2, 0, 14, 3 ], "texture": "#texture", "rotation": 90 }, "north": { "uv": [ 0, 2, 3, 14 ], "texture": "#texture" }, "south": { "uv": [ 13, 2, 16, 14 ], "texture": "#texture" }, "west": { "uv": [ 2, 2, 14, 14 ], "texture": "#texture" } diff --git a/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_right.json b/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_right.json index ff52e9d67..7ab452e94 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_right.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_right.json @@ -8,8 +8,8 @@ "from": [ 14, 4.5, 3.5 ], "to": [ 15.5, 12.5, 11.5 ], "faces": { - "down": { "uv": [ 0, 2, 3, 14 ], "texture": "#texture" }, - "up": { "uv": [ 0, 2, 3, 14 ], "texture": "#texture" }, + "down": { "uv": [ 2, 14, 14, 16 ], "texture": "#texture", "rotation": 90 }, + "up": { "uv": [ 2, 0, 14, 3 ], "texture": "#texture", "rotation": 270 }, "north": { "uv": [ 13, 2, 16, 14 ], "texture": "#texture" }, "south": { "uv": [ 0, 2, 3, 14 ], "texture": "#texture" }, "east": { "uv": [ 2, 2, 14, 14 ], "texture": "#texture" } 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 fa3783c51..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": [ { "tag": "forge:dusts/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 1ad34028d..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": [ { "tag": "forge:dusts/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/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/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/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/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/computer_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json deleted file mode 100644 index 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "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 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "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 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "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 6575281bb..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json +++ /dev/null @@ -1,11 +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 f6f9710c5..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json +++ /dev/null @@ -1,13 +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 bff665f73..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json +++ /dev/null @@ -1,13 +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 fff10863c..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json +++ /dev/null @@ -1,11 +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 735c12a91..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json +++ /dev/null @@ -1,13 +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 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "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 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "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 9a8a883df..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json +++ /dev/null @@ -1,13 +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 00dae5bc8..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json +++ /dev/null @@ -1,13 +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 cb88adee4..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json +++ /dev/null @@ -1,13 +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/bios.lua b/src/main/resources/data/computercraft/lua/bios.lua index 2913da090..f1e80cef4 100644 --- a/src/main/resources/data/computercraft/lua/bios.lua +++ b/src/main/resources/data/computercraft/lua/bios.lua @@ -21,7 +21,7 @@ if _VERSION == "Lua 5.1" then local nativeloadstring = loadstring local nativesetfenv = setfenv - --- Historically load/loadstring would handle the chunk name as if it has + -- Historically load/loadstring would handle the chunk name as if it has -- been prefixed with "=". We emulate that behaviour here. local function prefix(chunkname) if type(chunkname) ~= "string" then return chunkname end @@ -33,45 +33,43 @@ if _VERSION == "Lua 5.1" then end end - function load( x, name, mode, env ) + function load(x, name, mode, env) expect(1, x, "function", "string") expect(2, name, "string", "nil") expect(3, mode, "string", "nil") expect(4, env, "table", "nil") - local ok, p1, p2 = pcall( function() + local ok, p1, p2 = pcall(function() if type(x) == "string" then - local result, err = nativeloadstring( x, name ) + local result, err = nativeloadstring(x, name) if result then if env then env._ENV = env - nativesetfenv( result, env ) + nativesetfenv(result, env) end return result else return nil, err end else - local result, err = nativeload( x, name ) + local result, err = nativeload(x, name) if result then if env then env._ENV = env - nativesetfenv( result, env ) + nativesetfenv(result, env) end return result else return nil, err end end - end ) + end) if ok then return p1, p2 else - error( p1, 2 ) + error(p1, 2) end end - table.unpack = unpack - table.pack = function( ... ) return { n = select( "#", ... ), ... } end if _CC_DISABLE_LUA51_FEATURES then -- Remove the Lua 5.1 features that will be removed when we update to Lua 5.2, for compatibility testing. @@ -83,7 +81,7 @@ if _VERSION == "Lua 5.1" then math.log10 = nil table.maxn = nil else - loadstring = function(string, chunkname) return nativeloadstring(string, prefix( chunkname )) end + loadstring = function(string, chunkname) return nativeloadstring(string, prefix(chunkname)) end -- Inject a stub for the old bit library _G.bit = { @@ -98,97 +96,33 @@ if _VERSION == "Lua 5.1" then end end -if _VERSION == "Lua 5.3" and not bit32 then - -- If we're on Lua 5.3, install the bit32 api from Lua 5.2 - -- (Loaded from a string so this file will still parse on <5.3 lua) - load( [[ - bit32 = {} - - function bit32.arshift( n, bits ) - if type(n) ~= "number" or type(bits) ~= "number" then - error( "Expected number, number", 2 ) - end - return n >> bits - end - - function bit32.band( m, n ) - if type(m) ~= "number" or type(n) ~= "number" then - error( "Expected number, number", 2 ) - end - return m & n - end - - function bit32.bnot( n ) - if type(n) ~= "number" then - error( "Expected number", 2 ) - end - return ~n - end - - function bit32.bor( m, n ) - if type(m) ~= "number" or type(n) ~= "number" then - error( "Expected number, number", 2 ) - end - return m | n - end - - function bit32.btest( m, n ) - if type(m) ~= "number" or type(n) ~= "number" then - error( "Expected number, number", 2 ) - end - return (m & n) ~= 0 - end - - function bit32.bxor( m, n ) - if type(m) ~= "number" or type(n) ~= "number" then - error( "Expected number, number", 2 ) - end - return m ~ n - end - - function bit32.lshift( n, bits ) - if type(n) ~= "number" or type(bits) ~= "number" then - error( "Expected number, number", 2 ) - end - return n << bits - end - - function bit32.rshift( n, bits ) - if type(n) ~= "number" or type(bits) ~= "number" then - error( "Expected number, number", 2 ) - end - return n >> bits - end - ]] )() -end - -- Install lua parts of the os api function os.version() return "CraftOS 1.8" end -function os.pullEventRaw( sFilter ) - return coroutine.yield( sFilter ) +function os.pullEventRaw(sFilter) + return coroutine.yield(sFilter) end -function os.pullEvent( sFilter ) - local eventData = table.pack( os.pullEventRaw( sFilter ) ) +function os.pullEvent(sFilter) + local eventData = table.pack(os.pullEventRaw(sFilter)) if eventData[1] == "terminate" then - error( "Terminated", 0 ) + error("Terminated", 0) end - return table.unpack( eventData, 1, eventData.n ) + return table.unpack(eventData, 1, eventData.n) end -- Install globals -function sleep( nTime ) +function sleep(nTime) expect(1, nTime, "number", "nil") - local timer = os.startTimer( nTime or 0 ) + local timer = os.startTimer(nTime or 0) repeat - local _, param = os.pullEvent( "timer" ) + local _, param = os.pullEvent("timer") until param == timer end -function write( sText ) +function write(sText) expect(1, sText, "string", "number") local w, h = term.getSize() @@ -209,32 +143,32 @@ function write( sText ) -- Print the line with proper word wrapping sText = tostring(sText) while #sText > 0 do - local whitespace = string.match( sText, "^[ \t]+" ) + local whitespace = string.match(sText, "^[ \t]+") if whitespace then -- Print whitespace - term.write( whitespace ) + term.write(whitespace) x, y = term.getCursorPos() - sText = string.sub( sText, #whitespace + 1 ) + sText = string.sub(sText, #whitespace + 1) end - local newline = string.match( sText, "^\n" ) + local newline = string.match(sText, "^\n") if newline then -- Print newlines newLine() - sText = string.sub( sText, 2 ) + sText = string.sub(sText, 2) end - local text = string.match( sText, "^[^ \t\n]+" ) + local text = string.match(sText, "^[^ \t\n]+") if text then - sText = string.sub( sText, #text + 1 ) + sText = string.sub(sText, #text + 1) if #text > w then -- Print a multiline word while #text > 0 do if x > w then newLine() end - term.write( text ) - text = string.sub( text, w - x + 2 ) + term.write(text) + text = string.sub(text, w - x + 2) x, y = term.getCursorPos() end else @@ -242,7 +176,7 @@ function write( sText ) if x + #text - 1 > w then newLine() end - term.write( text ) + term.write(text) x, y = term.getCursorPos() end end @@ -251,42 +185,42 @@ function write( sText ) return nLinesPrinted end -function print( ... ) +function print(...) local nLinesPrinted = 0 - local nLimit = select("#", ... ) + local nLimit = select("#", ...) for n = 1, nLimit do - local s = tostring( select( n, ... ) ) + local s = tostring(select(n, ...)) if n < nLimit then s = s .. "\t" end - nLinesPrinted = nLinesPrinted + write( s ) + nLinesPrinted = nLinesPrinted + write(s) end - nLinesPrinted = nLinesPrinted + write( "\n" ) + nLinesPrinted = nLinesPrinted + write("\n") return nLinesPrinted end -function printError( ... ) +function printError(...) local oldColour if term.isColour() then oldColour = term.getTextColour() - term.setTextColour( colors.red ) + term.setTextColour(colors.red) end - print( ... ) + print(...) if term.isColour() then - term.setTextColour( oldColour ) + term.setTextColour(oldColour) end end -function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) +function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) expect(1, _sReplaceChar, "string", "nil") expect(2, _tHistory, "table", "nil") expect(3, _fnComplete, "function", "nil") expect(4, _sDefault, "string", "nil") - term.setCursorBlink( true ) + term.setCursorBlink(true) local sLine - if type( _sDefault ) == "string" then + if type(_sDefault) == "string" then sLine = _sDefault else sLine = "" @@ -294,14 +228,14 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) local nHistoryPos local nPos, nScroll = #sLine, 0 if _sReplaceChar then - _sReplaceChar = string.sub( _sReplaceChar, 1, 1 ) + _sReplaceChar = string.sub(_sReplaceChar, 1, 1) end local tCompletions local nCompletion local function recomplete() if _fnComplete and nPos == #sLine then - tCompletions = _fnComplete( sLine ) + tCompletions = _fnComplete(sLine) if tCompletions and #tCompletions > 0 then nCompletion = 1 else @@ -321,7 +255,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) local w = term.getSize() local sx = term.getCursorPos() - local function redraw( _bClear ) + local function redraw(_bClear) local cursor_pos = nPos - nScroll if sx + cursor_pos >= w then -- We've moved beyond the RHS, ensure we're on the edge. @@ -332,39 +266,39 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) end local _, cy = term.getCursorPos() - term.setCursorPos( sx, cy ) + term.setCursorPos(sx, cy) local sReplace = _bClear and " " or _sReplaceChar if sReplace then - term.write( string.rep( sReplace, math.max( #sLine - nScroll, 0 ) ) ) + term.write(string.rep(sReplace, math.max(#sLine - nScroll, 0))) else - term.write( string.sub( sLine, nScroll + 1 ) ) + term.write(string.sub(sLine, nScroll + 1)) end if nCompletion then - local sCompletion = tCompletions[ nCompletion ] + local sCompletion = tCompletions[nCompletion] local oldText, oldBg if not _bClear then oldText = term.getTextColor() oldBg = term.getBackgroundColor() - term.setTextColor( colors.white ) - term.setBackgroundColor( colors.gray ) + term.setTextColor(colors.white) + term.setBackgroundColor(colors.gray) end if sReplace then - term.write( string.rep( sReplace, #sCompletion ) ) + term.write(string.rep(sReplace, #sCompletion)) else - term.write( sCompletion ) + term.write(sCompletion) end if not _bClear then - term.setTextColor( oldText ) - term.setBackgroundColor( oldBg ) + term.setTextColor(oldText) + term.setBackgroundColor(oldBg) end end - term.setCursorPos( sx + nPos - nScroll, cy ) + term.setCursorPos(sx + nPos - nScroll, cy) end local function clear() - redraw( true ) + redraw(true) end recomplete() @@ -376,7 +310,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) clear() -- Find the common prefix of all the other suggestions which start with the same letter as the current one - local sCompletion = tCompletions[ nCompletion ] + local sCompletion = tCompletions[nCompletion] sLine = sLine .. sCompletion nPos = #sLine @@ -390,7 +324,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) if sEvent == "char" then -- Typed key clear() - sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 ) + sLine = string.sub(sLine, 1, nPos) .. param .. string.sub(sLine, nPos + 1) nPos = nPos + 1 recomplete() redraw() @@ -398,7 +332,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) elseif sEvent == "paste" then -- Pasted text clear() - sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 ) + sLine = string.sub(sLine, 1, nPos) .. param .. string.sub(sLine, nPos + 1) nPos = nPos + #param recomplete() redraw() @@ -489,7 +423,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) -- Backspace if nPos > 0 then clear() - sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 ) + sLine = string.sub(sLine, 1, nPos - 1) .. string.sub(sLine, nPos + 1) nPos = nPos - 1 if nScroll > 0 then nScroll = nScroll - 1 end recomplete() @@ -509,7 +443,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) -- Delete if nPos < #sLine then clear() - sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 ) + sLine = string.sub(sLine, 1, nPos) .. string.sub(sLine, nPos + 2) recomplete() redraw() end @@ -546,14 +480,14 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) end local _, cy = term.getCursorPos() - term.setCursorBlink( false ) - term.setCursorPos( w + 1, cy ) + term.setCursorBlink(false) + term.setCursorPos(w + 1, cy) print() return sLine end -function loadfile( filename, mode, env ) +function loadfile(filename, mode, env) -- Support the previous `loadfile(filename, env)` form instead. if type(mode) == "table" and env == nil then mode, env = nil, mode @@ -563,81 +497,81 @@ function loadfile( filename, mode, env ) expect(2, mode, "string", "nil") expect(3, env, "table", "nil") - local file = fs.open( filename, "r" ) + local file = fs.open(filename, "r") if not file then return nil, "File not found" end - local func, err = load( file.readAll(), "@" .. fs.getName( filename ), mode, env ) + local func, err = load(file.readAll(), "@" .. fs.getName(filename), mode, env) file.close() return func, err end -function dofile( _sFile ) +function dofile(_sFile) expect(1, _sFile, "string") - local fnFile, e = loadfile( _sFile, nil, _G ) + local fnFile, e = loadfile(_sFile, nil, _G) if fnFile then return fnFile() else - error( e, 2 ) + error(e, 2) end end -- Install the rest of the OS api -function os.run( _tEnv, _sPath, ... ) +function os.run(_tEnv, _sPath, ...) expect(1, _tEnv, "table") expect(2, _sPath, "string") - local tArgs = table.pack( ... ) + local tArgs = table.pack(...) local tEnv = _tEnv - setmetatable( tEnv, { __index = _G } ) - local fnFile, err = loadfile( _sPath, nil, tEnv ) + setmetatable(tEnv, { __index = _G }) + local fnFile, err = loadfile(_sPath, nil, tEnv) if fnFile then - local ok, err = pcall( function() - fnFile( table.unpack( tArgs, 1, tArgs.n ) ) - end ) + local ok, err = pcall(function() + fnFile(table.unpack(tArgs, 1, tArgs.n)) + end) if not ok then if err and err ~= "" then - printError( err ) + printError(err) end return false end return true end if err and err ~= "" then - printError( err ) + printError(err) end return false end local tAPIsLoading = {} -function os.loadAPI( _sPath ) +function os.loadAPI(_sPath) expect(1, _sPath, "string") - local sName = fs.getName( _sPath ) + local sName = fs.getName(_sPath) if sName:sub(-4) == ".lua" then sName = sName:sub(1, -5) end if tAPIsLoading[sName] == true then - printError( "API " .. sName .. " is already being loaded" ) + printError("API " .. sName .. " is already being loaded") return false end tAPIsLoading[sName] = true local tEnv = {} - setmetatable( tEnv, { __index = _G } ) - local fnAPI, err = loadfile( _sPath, nil, tEnv ) + setmetatable(tEnv, { __index = _G }) + local fnAPI, err = loadfile(_sPath, nil, tEnv) if fnAPI then - local ok, err = pcall( fnAPI ) + local ok, err = pcall(fnAPI) if not ok then tAPIsLoading[sName] = nil - return error( "Failed to load API " .. sName .. " due to " .. err, 1 ) + return error("Failed to load API " .. sName .. " due to " .. err, 1) end else tAPIsLoading[sName] = nil - return error( "Failed to load API " .. sName .. " due to " .. err, 1 ) + return error("Failed to load API " .. sName .. " due to " .. err, 1) end local tAPI = {} - for k, v in pairs( tEnv ) do + for k, v in pairs(tEnv) do if k ~= "_ENV" then tAPI[k] = v end @@ -648,15 +582,15 @@ function os.loadAPI( _sPath ) return true end -function os.unloadAPI( _sName ) +function os.unloadAPI(_sName) expect(1, _sName, "string") if _sName ~= "_G" and type(_G[_sName]) == "table" then _G[_sName] = nil end end -function os.sleep( nTime ) - sleep( nTime ) +function os.sleep(nTime) + sleep(nTime) end local nativeShutdown = os.shutdown @@ -685,7 +619,7 @@ if http then PATCH = true, TRACE = true, } - local function checkKey( options, key, ty, opt ) + local function checkKey(options, key, ty, opt) local value = options[key] local valueTy = type(value) @@ -694,24 +628,24 @@ if http then end end - local function checkOptions( options, body ) - checkKey( options, "url", "string") + local function checkOptions(options, body) + checkKey(options, "url", "string") if body == false then - checkKey( options, "body", "nil" ) + checkKey(options, "body", "nil") else - checkKey( options, "body", "string", not body ) + checkKey(options, "body", "string", not body) end - checkKey( options, "headers", "table", true ) - checkKey( options, "method", "string", true ) - checkKey( options, "redirect", "boolean", true ) + checkKey(options, "headers", "table", true) + checkKey(options, "method", "string", true) + checkKey(options, "redirect", "boolean", true) if options.method and not methods[options.method] then - error( "Unsupported HTTP method", 3 ) + error("Unsupported HTTP method", 3) end end - local function wrapRequest( _url, ... ) - local ok, err = nativeHTTPRequest( ... ) + local function wrapRequest(_url, ...) + local ok, err = nativeHTTPRequest(...) if ok then while true do local event, param1, param2, param3 = os.pullEvent() @@ -725,35 +659,35 @@ if http then return nil, err end - http.get = function( _url, _headers, _binary) - if type( _url ) == "table" then - checkOptions( _url, false ) - return wrapRequest( _url.url, _url ) + http.get = function(_url, _headers, _binary) + if type(_url) == "table" then + checkOptions(_url, false) + return wrapRequest(_url.url, _url) end expect(1, _url, "string") expect(2, _headers, "table", "nil") expect(3, _binary, "boolean", "nil") - return wrapRequest( _url, _url, nil, _headers, _binary ) + return wrapRequest(_url, _url, nil, _headers, _binary) end - http.post = function( _url, _post, _headers, _binary) - if type( _url ) == "table" then - checkOptions( _url, true ) - return wrapRequest( _url.url, _url ) + http.post = function(_url, _post, _headers, _binary) + if type(_url) == "table" then + checkOptions(_url, true) + return wrapRequest(_url.url, _url) end expect(1, _url, "string") expect(2, _post, "string") expect(3, _headers, "table", "nil") expect(4, _binary, "boolean", "nil") - return wrapRequest( _url, _url, _post, _headers, _binary ) + return wrapRequest(_url, _url, _post, _headers, _binary) end - http.request = function( _url, _post, _headers, _binary ) + http.request = function(_url, _post, _headers, _binary) local url - if type( _url ) == "table" then - checkOptions( _url ) + if type(_url) == "table" then + checkOptions(_url) url = _url.url else expect(1, _url, "string") @@ -763,32 +697,32 @@ if http then url = _url.url end - local ok, err = nativeHTTPRequest( _url, _post, _headers, _binary ) + local ok, err = nativeHTTPRequest(_url, _post, _headers, _binary) if not ok then - os.queueEvent( "http_failure", url, err ) + os.queueEvent("http_failure", url, err) end return ok, err end local nativeCheckURL = http.checkURL http.checkURLAsync = nativeCheckURL - http.checkURL = function( _url ) - local ok, err = nativeCheckURL( _url ) + http.checkURL = function(_url) + local ok, err = nativeCheckURL(_url) if not ok then return ok, err end while true do - local _, url, ok, err = os.pullEvent( "http_check" ) + local _, url, ok, err = os.pullEvent("http_check") if url == _url then return ok, err end end end local nativeWebsocket = http.websocket http.websocketAsync = nativeWebsocket - http.websocket = function( _url, _headers ) + http.websocket = function(_url, _headers) expect(1, _url, "string") expect(2, _headers, "table", "nil") - local ok, err = nativeWebsocket( _url, _headers ) + local ok, err = nativeWebsocket(_url, _headers) if not ok then return ok, err end while true do @@ -804,7 +738,7 @@ end -- Install the lua part of the FS api local tEmpty = {} -function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs ) +function fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) expect(1, sPath, "string") expect(2, sLocation, "string") expect(3, bIncludeFiles, "boolean", "nil") @@ -814,49 +748,49 @@ function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs ) bIncludeDirs = bIncludeDirs ~= false local sDir = sLocation local nStart = 1 - local nSlash = string.find( sPath, "[/\\]", nStart ) + local nSlash = string.find(sPath, "[/\\]", nStart) if nSlash == 1 then sDir = "" nStart = 2 end local sName while not sName do - local nSlash = string.find( sPath, "[/\\]", nStart ) + local nSlash = string.find(sPath, "[/\\]", nStart) if nSlash then - local sPart = string.sub( sPath, nStart, nSlash - 1 ) - sDir = fs.combine( sDir, sPart ) + local sPart = string.sub(sPath, nStart, nSlash - 1) + sDir = fs.combine(sDir, sPart) nStart = nSlash + 1 else - sName = string.sub( sPath, nStart ) + sName = string.sub(sPath, nStart) end end - if fs.isDir( sDir ) then + if fs.isDir(sDir) then local tResults = {} if bIncludeDirs and sPath == "" then - table.insert( tResults, "." ) + table.insert(tResults, ".") end if sDir ~= "" then if sPath == "" then - table.insert( tResults, bIncludeDirs and ".." or "../" ) + table.insert(tResults, bIncludeDirs and ".." or "../") elseif sPath == "." then - table.insert( tResults, bIncludeDirs and "." or "./" ) + table.insert(tResults, bIncludeDirs and "." or "./") end end - local tFiles = fs.list( sDir ) + local tFiles = fs.list(sDir) for n = 1, #tFiles do local sFile = tFiles[n] - if #sFile >= #sName and string.sub( sFile, 1, #sName ) == sName then - local bIsDir = fs.isDir( fs.combine( sDir, sFile ) ) - local sResult = string.sub( sFile, #sName + 1 ) + if #sFile >= #sName and string.sub(sFile, 1, #sName) == sName then + local bIsDir = fs.isDir(fs.combine(sDir, sFile)) + local sResult = string.sub(sFile, #sName + 1) if bIsDir then - table.insert( tResults, sResult .. "/" ) + table.insert(tResults, sResult .. "/") if bIncludeDirs and #sResult > 0 then - table.insert( tResults, sResult ) + table.insert(tResults, sResult) end else if bIncludeFiles and #sResult > 0 then - table.insert( tResults, sResult ) + table.insert(tResults, sResult) end end end @@ -868,26 +802,26 @@ end -- Load APIs local bAPIError = false -local tApis = fs.list( "rom/apis" ) -for _, sFile in ipairs( tApis ) do - if string.sub( sFile, 1, 1 ) ~= "." then - local sPath = fs.combine( "rom/apis", sFile ) - if not fs.isDir( sPath ) then - if not os.loadAPI( sPath ) then +local tApis = fs.list("rom/apis") +for _, sFile in ipairs(tApis) do + if string.sub(sFile, 1, 1) ~= "." then + local sPath = fs.combine("rom/apis", sFile) + if not fs.isDir(sPath) then + if not os.loadAPI(sPath) then bAPIError = true end end end end -if turtle and fs.isDir( "rom/apis/turtle" ) then +if turtle and fs.isDir("rom/apis/turtle") then -- Load turtle APIs - local tApis = fs.list( "rom/apis/turtle" ) - for _, sFile in ipairs( tApis ) do - if string.sub( sFile, 1, 1 ) ~= "." then - local sPath = fs.combine( "rom/apis/turtle", sFile ) - if not fs.isDir( sPath ) then - if not os.loadAPI( sPath ) then + local tApis = fs.list("rom/apis/turtle") + for _, sFile in ipairs(tApis) do + if string.sub(sFile, 1, 1) ~= "." then + local sPath = fs.combine("rom/apis/turtle", sFile) + if not fs.isDir(sPath) then + if not os.loadAPI(sPath) then bAPIError = true end end @@ -895,14 +829,14 @@ if turtle and fs.isDir( "rom/apis/turtle" ) then end end -if pocket and fs.isDir( "rom/apis/pocket" ) then +if pocket and fs.isDir("rom/apis/pocket") then -- Load pocket APIs - local tApis = fs.list( "rom/apis/pocket" ) - for _, sFile in ipairs( tApis ) do - if string.sub( sFile, 1, 1 ) ~= "." then - local sPath = fs.combine( "rom/apis/pocket", sFile ) - if not fs.isDir( sPath ) then - if not os.loadAPI( sPath ) then + local tApis = fs.list("rom/apis/pocket") + for _, sFile in ipairs(tApis) do + if string.sub(sFile, 1, 1) ~= "." then + local sPath = fs.combine("rom/apis/pocket", sFile) + if not fs.isDir(sPath) then + if not os.loadAPI(sPath) then bAPIError = true end end @@ -910,18 +844,18 @@ if pocket and fs.isDir( "rom/apis/pocket" ) then end end -if commands and fs.isDir( "rom/apis/command" ) then +if commands and fs.isDir("rom/apis/command") then -- Load command APIs - if os.loadAPI( "rom/apis/command/commands.lua" ) then + if os.loadAPI("rom/apis/command/commands.lua") then -- Add a special case-insensitive metatable to the commands api local tCaseInsensitiveMetatable = { - __index = function( table, key ) - local value = rawget( table, key ) + __index = function(table, key) + local value = rawget(table, key) if value ~= nil then return value end if type(key) == "string" then - local value = rawget( table, string.lower(key) ) + local value = rawget(table, string.lower(key)) if value ~= nil then return value end @@ -929,8 +863,8 @@ if commands and fs.isDir( "rom/apis/command" ) then return nil end, } - setmetatable( commands, tCaseInsensitiveMetatable ) - setmetatable( commands.async, tCaseInsensitiveMetatable ) + setmetatable(commands, tCaseInsensitiveMetatable) + setmetatable(commands.async, tCaseInsensitiveMetatable) -- Add global "exec" function exec = commands.exec @@ -940,29 +874,77 @@ if commands and fs.isDir( "rom/apis/command" ) then end if bAPIError then - print( "Press any key to continue" ) - os.pullEvent( "key" ) + print("Press any key to continue") + os.pullEvent("key") term.clear() - term.setCursorPos( 1, 1 ) + term.setCursorPos(1, 1) end -- Set default settings -settings.set( "shell.allow_startup", true ) -settings.set( "shell.allow_disk_startup", commands == nil ) -settings.set( "shell.autocomplete", true ) -settings.set( "edit.autocomplete", true ) -settings.set( "edit.default_extension", "lua" ) -settings.set( "paint.default_extension", "nfp" ) -settings.set( "lua.autocomplete", true ) -settings.set( "list.show_hidden", false ) -settings.set( "motd.enable", false ) -settings.set( "motd.path", "/rom/motd.txt:/motd.txt" ) +settings.define("shell.allow_startup", { + default = true, + description = "Run startup files when the computer turns on.", + type = "boolean", +}) +settings.define("shell.allow_disk_startup", { + default = commands == nil, + description = "Run startup files from disk drives when the computer turns on.", + type = "boolean", +}) + +settings.define("shell.autocomplete", { + default = true, + description = "Autocomplete program and arguments in the shell.", + type = "boolean", +}) +settings.define("edit.autocomplete", { + default = true, + description = "Autocomplete API and function names in the editor.", + type = "boolean", +}) +settings.define("lua.autocomplete", { + default = true, + description = "Autocomplete API and function names in the Lua REPL.", + type = "boolean", +}) + +settings.define("edit.default_extension", { + default = "lua", + description = [[The file extension the editor will use if none is given. Set to "" to disable.]], + type = "string", +}) +settings.define("paint.default_extension", { + default = "nfp", + description = [[The file extension the paint program will use if none is given. Set to "" to disable.]], + type = "string", +}) + +settings.define("list.show_hidden", { + default = false, + description = [[Show hidden files (those starting with "." in the Lua REPL)]], + type = "boolean", +}) + +settings.define("motd.enable", { + default = false, + description = "Display a random message when the computer starts up.", + type = "boolean", +}) +settings.define("motd.path", { + default = "/rom/motd.txt:/motd.txt", + description = [[The path to load random messages from. Should be a colon (":") separated string of file paths.]], + type = "string", +}) if term.isColour() then - settings.set( "bios.use_multishell", true ) + settings.define("bios.use_multishell", { + default = true, + description = [[Allow running multiple programs at once, through the use of the "fg" and "bg" programs.]], + type = "boolean", + }) end if _CC_DEFAULT_SETTINGS then - for sPair in string.gmatch( _CC_DEFAULT_SETTINGS, "[^,]+" ) do - local sName, sValue = string.match( sPair, "([^=]*)=(.*)" ) + for sPair in string.gmatch(_CC_DEFAULT_SETTINGS, "[^,]+") do + local sName, sValue = string.match(sPair, "([^=]*)=(.*)") if sName and sValue then local value if sValue == "true" then @@ -977,46 +959,43 @@ if _CC_DEFAULT_SETTINGS then value = sValue end if value ~= nil then - settings.set( sName, value ) + settings.set(sName, value) else - settings.unset( sName ) + settings.unset(sName) end end end end -- Load user settings -if fs.exists( ".settings" ) then - settings.load( ".settings" ) +if fs.exists(".settings") then + settings.load(".settings") end -- Run the shell -local ok, err = pcall( function() - parallel.waitForAny( - function() - local sShell - if term.isColour() and settings.get( "bios.use_multishell" ) then - sShell = "rom/programs/advanced/multishell.lua" - else - sShell = "rom/programs/shell.lua" - end - os.run( {}, sShell ) - os.run( {}, "rom/programs/shutdown.lua" ) - end, - function() - rednet.run() - end ) -end ) +local ok, err = pcall(parallel.waitForAny, + function() + local sShell + if term.isColour() and settings.get("bios.use_multishell") then + sShell = "rom/programs/advanced/multishell.lua" + else + sShell = "rom/programs/shell.lua" + end + os.run({}, sShell) + os.run({}, "rom/programs/shutdown.lua") + end, + rednet.run +) -- If the shell errored, let the user read it. -term.redirect( term.native() ) +term.redirect(term.native()) if not ok then - printError( err ) - pcall( function() - term.setCursorBlink( false ) - print( "Press any key to continue" ) - os.pullEvent( "key" ) - end ) + printError(err) + pcall(function() + term.setCursorBlink(false) + print("Press any key to continue") + os.pullEvent("key") + end) end -- End diff --git a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua index b2e665268..b821c38d3 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua @@ -1,24 +1,92 @@ +--- The Colors API allows you to manipulate sets of colors. +-- +-- This is useful in conjunction with Bundled Cables from the RedPower mod, +-- RedNet Cables from the MineFactory Reloaded mod, and colors on Advanced +-- Computers and Advanced Monitors. +-- +-- For the non-American English version just replace @{colors} with @{colours} +-- and it will use the other API, colours which is exactly the same, except in +-- British English (e.g. @{colors.gray} is spelt @{colours.grey}). +-- +-- @see colours +-- @module colors + local expect = dofile("rom/modules/main/cc/expect.lua").expect --- Colors -white = 1 -orange = 2 -magenta = 4 -lightBlue = 8 -yellow = 16 -lime = 32 -pink = 64 -gray = 128 -lightGray = 256 -cyan = 512 -purple = 1024 -blue = 2048 -brown = 4096 -green = 8192 -red = 16384 -black = 32768 +--- White: Written as `0` in paint files and @{term.blit}, has a default +-- terminal colour of #F0F0F0. +white = 0x1 -function combine( ... ) +--- Orange: Written as `1` in paint files and @{term.blit}, has a +-- default terminal colour of #F2B233. +orange = 0x2 + +--- Magenta: Written as `2` in paint files and @{term.blit}, has a +-- default terminal colour of #E57FD8. +magenta = 0x4 + +--- Light blue: Written as `3` in paint files and @{term.blit}, has a +-- default terminal colour of #99B2F2. +lightBlue = 0x8 + +--- Yellow: Written as `4` in paint files and @{term.blit}, has a +-- default terminal colour of #DEDE6C. +yellow = 0x10 + +--- Lime: Written as `5` in paint files and @{term.blit}, has a default +-- terminal colour of #7FCC19. +lime = 0x20 + +--- Pink. Written as `6` in paint files and @{term.blit}, has a default +-- terminal colour of #F2B2CC. +pink = 0x40 + +--- Gray: Written as `7` in paint files and @{term.blit}, has a default +-- terminal colour of #4C4C4C. +gray = 0x80 + +--- Light gray: Written as `8` in paint files and @{term.blit}, has a +-- default terminal colour of #999999. +lightGray = 0x100 + +--- Cyan: Written as `9` in paint files and @{term.blit}, has a default +-- terminal colour of #4C99B2. +cyan = 0x200 + +--- Purple: Written as `a` in paint files and @{term.blit}, has a +-- default terminal colour of #B266E5. +purple = 0x400 + +--- Blue: Written as `b` in paint files and @{term.blit}, has a default +-- terminal colour of #3366CC. +blue = 0x800 + +--- Brown: Written as `c` in paint files and @{term.blit}, has a default +-- terminal colour of #7F664C. +brown = 0x1000 + +--- Green: Written as `d` in paint files and @{term.blit}, has a default +-- terminal colour of #57A64E. +green = 0x2000 + +--- Red: Written as `e` in paint files and @{term.blit}, has a default +-- terminal colour of #CC4C4C. +red = 0x4000 + +--- Black: Written as `f` in paint files and @{term.blit}, has a default +-- terminal colour of #191919. +black = 0x8000 + +--- Combines a set of colors (or sets of colors) into a larger set. +-- +-- @tparam number ... The colors to combine. +-- @treturn number The union of the color sets given in `...` +-- @usage +-- ```lua +-- colors.combine(colors.white, colors.magenta, colours.lightBlue) +-- -- => 13 +-- ``` +function combine(...) local r = 0 for i = 1, select('#', ...) do local c = select(i, ...) @@ -28,7 +96,21 @@ function combine( ... ) return r end -function subtract( colors, ... ) +--- Removes one or more colors (or sets of colors) from an initial set. +-- +-- Each parameter beyond the first may be a single color or may be a set of +-- colors (in the latter case, all colors in the set are removed from the +-- original set). +-- +-- @tparam number colors The color from which to subtract. +-- @tparam number ... The colors to subtract. +-- @treturn number The resulting color. +-- @usage +-- ```lua +-- colours.subtract(colours.lime, colours.orange, colours.white) +-- -- => 32 +-- ``` +function subtract(colors, ...) expect(1, colors, "number") local r = colors for i = 1, select('#', ...) do @@ -39,34 +121,91 @@ function subtract( colors, ... ) return r end -function test( colors, color ) +--- Tests whether `color` is contained within `colors`. +-- +-- @tparam number colors A color, or color set +-- @tparam number color A color or set of colors that `colors` should contain. +-- @treturn boolean If `colors` contains all colors within `color`. +-- @usage +-- ```lua +-- colors.test(colors.combine(colors.white, colors.magenta, colours.lightBlue), colors.lightBlue) +-- -- => true +-- ``` +function test(colors, color) expect(1, colors, "number") expect(2, color, "number") return bit32.band(colors, color) == color end -function packRGB( r, g, b ) +--- Combine a three-colour RGB value into one hexadecimal representation. +-- +-- @tparam number r The red channel, should be between 0 and 1. +-- @tparam number g The red channel, should be between 0 and 1. +-- @tparam number b The blue channel, should be between 0 and 1. +-- @treturn number The combined hexadecimal colour. +-- @usage +-- ```lua +-- colors.rgb(0.7, 0.2, 0.6) +-- -- => 0xb23399 +-- ``` +function packRGB(r, g, b) expect(1, r, "number") expect(2, g, "number") expect(3, b, "number") return - bit32.band( r * 255, 0xFF ) * 2 ^ 16 + - bit32.band( g * 255, 0xFF ) * 2 ^ 8 + - bit32.band( b * 255, 0xFF ) + bit32.band(r * 255, 0xFF) * 2 ^ 16 + + bit32.band(g * 255, 0xFF) * 2 ^ 8 + + bit32.band(b * 255, 0xFF) end -function unpackRGB( rgb ) +--- Separate a hexadecimal RGB colour into its three constituent channels. +-- +-- @tparam number rgb The combined hexadecimal colour. +-- @treturn number The red channel, will be between 0 and 1. +-- @treturn number The red channel, will be between 0 and 1. +-- @treturn number The blue channel, will be between 0 and 1. +-- @usage +-- ```lua +-- colors.rgb(0xb23399) +-- -- => 0.7, 0.2, 0.6 +-- ``` +-- @see colors.packRGB +function unpackRGB(rgb) expect(1, rgb, "number") return - bit32.band( bit32.rshift( rgb, 16 ), 0xFF ) / 255, - bit32.band( bit32.rshift( rgb, 8 ), 0xFF ) / 255, - bit32.band( rgb, 0xFF ) / 255 + bit32.band(bit32.rshift(rgb, 16), 0xFF) / 255, + bit32.band(bit32.rshift(rgb, 8), 0xFF) / 255, + bit32.band(rgb, 0xFF) / 255 end -function rgb8( r, g, b ) +--- Either calls @{colors.packRGB} or @{colors.unpackRGB}, depending on how many +-- arguments it receives. +-- +-- **Note:** This function is deprecated, and it is recommended you use the +-- specific pack/unpack function directly. +-- +-- @tparam[1] number r The red channel, as an argument to @{colors.packRGB}. +-- @tparam[1] number g The green channel, as an argument to @{colors.packRGB}. +-- @tparam[1] number b The blue channel, as an argument to @{colors.packRGB}. +-- @tparam[2] number rgb The combined hexadecimal color, as an argument to @{colors.unpackRGB}. +-- @treturn[1] number The combined hexadecimal colour, as returned by @{colors.packRGB}. +-- @treturn[2] number The red channel, as returned by @{colors.unpackRGB} +-- @treturn[2] number The green channel, as returned by @{colors.unpackRGB} +-- @treturn[2] number The blue channel, as returned by @{colors.unpackRGB} +-- @usage +-- ```lua +-- colors.rgb(0xb23399) +-- -- => 0.7, 0.2, 0.6 +-- ``` +-- @usage +-- ```lua +-- colors.rgb(0.7, 0.2, 0.6) +-- -- => 0xb23399 +-- ``` +function rgb8(r, g, b) if g == nil and b == nil then - return unpackRGB( r ) + return unpackRGB(r) else - return packRGB( r, g, b ) + return packRGB(r, g, b) end end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/colours.lua b/src/main/resources/data/computercraft/lua/rom/apis/colours.lua index fa17c6cb3..74f048df7 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/colours.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/colours.lua @@ -1,11 +1,23 @@ --- Colours (for lovers of british spelling) +--- Colours for lovers of British spelling. +-- +-- @see colors +-- @module colours + local colours = _ENV for k, v in pairs(colors) do colours[k] = v end +--- Grey. Written as `7` in paint files and @{term.blit}, has a default +-- terminal colour of #4C4C4C. +-- +-- @see colors.gray colours.grey = colors.gray -colours.gray = nil +colours.gray = nil --- @local +--- Light grey. Written as `8` in paint files and @{term.blit}, has a +-- default terminal colour of #999999. +-- +-- @see colors.lightGray colours.lightGrey = colors.lightGray -colours.lightGray = nil +colours.lightGray = nil --- @local diff --git a/src/main/resources/data/computercraft/lua/rom/apis/command/commands.lua b/src/main/resources/data/computercraft/lua/rom/apis/command/commands.lua index 41caa483f..5877c1b8e 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/command/commands.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/command/commands.lua @@ -1,20 +1,38 @@ +--- The commands API allows your system to directly execute [Minecraft +-- commands][mc] and gather data from the results. +-- +-- While one may use @{commands.exec} directly to execute a command, the +-- commands API also provides helper methods to execute every command. For +-- instance, `commands.say("Hi!")` is equivalent to `commands.exec("say Hi!")`. +-- +-- @{commands.async} provides a similar interface to execute asynchronous +-- commands. `commands.async.say("Hi!")` is equivalent to +-- `commands.execAsync("Hi!")`. +-- +-- [mc]: https://minecraft.gamepedia.com/Commands +-- +-- @module commands if not commands then - error( "Cannot load command API on normal computer", 2 ) + error("Cannot load command API on normal computer", 2) end +--- The builtin commands API, without any generated command helper functions +-- +-- This may be useful if a built-in function (such as @{commands.list}) has been +-- overwritten by a command. local native = commands.native or commands -local function collapseArgs( bJSONIsNBT, ... ) +local function collapseArgs(bJSONIsNBT, ...) local args = table.pack(...) for i = 1, #args do local arg = args[i] if type(arg) == "boolean" or type(arg) == "number" or type(arg) == "string" then args[i] = tostring(arg) elseif type(arg) == "table" then - args[i] = textutils.serialiseJSON( arg, bJSONIsNBT ) + args[i] = textutils.serialiseJSON(arg, bJSONIsNBT) else - error( "Expected string, number, boolean or table", 3 ) + error("Expected string, number, boolean or table", 3) end end @@ -24,22 +42,22 @@ end -- Put native functions into the environment local env = _ENV env.native = native -for k,v in pairs( native ) do +for k, v in pairs(native) do env[k] = v end -- Create wrapper functions for all the commands local tAsync = {} local tNonNBTJSONCommands = { - [ "tellraw" ] = true, - [ "title" ] = true + ["tellraw"] = true, + ["title"] = true, } local command_mt = {} function command_mt.__call(self, ...) local meta = self[command_mt] - local sCommand = collapseArgs( meta.json, table.concat(meta.name, " "), ... ) - return meta.func( sCommand ) + local sCommand = collapseArgs(meta.json, table.concat(meta.name, " "), ...) + return meta.func(sCommand) end function command_mt.__tostring(self) @@ -47,6 +65,16 @@ function command_mt.__tostring(self) return ("command %q"):format("/" .. table.concat(meta.name, " ")) end +local function mk_command(name, json, func) + return setmetatable({ + [command_mt] = { + name = name, + func = func, + json = json, + }, + }, command_mt) +end + function command_mt.__index(self, key) local meta = self[command_mt] if meta.children then return nil end @@ -56,31 +84,17 @@ function command_mt.__index(self, key) for _, child in ipairs(native.list(table.unpack(name))) do local child_name = { table.unpack(name) } child_name[#child_name + 1] = child - - self[child] = setmetatable({ [command_mt] = { - name = child_name, - func = meta.func, - json = meta.json - } }, command_mt) + self[child] = mk_command(child_name, meta.json, meta.func) end return self[key] end for _, sCommandName in ipairs(native.list()) do - if env[ sCommandName ] == nil then - local bJSONIsNBT = tNonNBTJSONCommands[ sCommandName ] == nil - env[ sCommandName ] = setmetatable({ [command_mt] = { - name = { sCommandName }, - func = native.exec, - json = bJSONIsNBT - } }, command_mt) - - tAsync[ sCommandName ] = setmetatable({ [command_mt] = { - name = { sCommandName }, - func = native.execAsync, - json = bJSONIsNBT - } }, command_mt) + if env[sCommandName] == nil then + local bJSONIsNBT = tNonNBTJSONCommands[sCommandName] == nil + env[sCommandName] = mk_command({ sCommandName }, bJSONIsNBT, native.exec) + tAsync[sCommandName] = mk_command({ sCommandName }, bJSONIsNBT, native.execAsync) end end env.async = tAsync diff --git a/src/main/resources/data/computercraft/lua/rom/apis/disk.lua b/src/main/resources/data/computercraft/lua/rom/apis/disk.lua index 7a0dbad39..fcc907121 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/disk.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/disk.lua @@ -1,87 +1,171 @@ +--- The Disk API allows you to interact with disk drives. +-- +-- These functions can operate on locally attached or remote disk drives. To use +-- a locally attached drive, specify “side” as one of the six sides +-- (e.g. `left`); to use a remote disk drive, specify its name as printed when +-- enabling its modem (e.g. `drive_0`). +-- +-- **Note:** All computers (except command computers), turtles and pocket +-- computers can be placed within a disk drive to access it's internal storage +-- like a disk. +-- +-- @module disk -local function isDrive( name ) - if type( name ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( name ) .. ")", 3 ) +local function isDrive(name) + if type(name) ~= "string" then + error("bad argument #1 (expected string, got " .. type(name) .. ")", 3) end - return peripheral.getType( name ) == "drive" + return peripheral.getType(name) == "drive" end -function isPresent( name ) - if isDrive( name ) then - return peripheral.call( name, "isDiskPresent" ) +--- Checks whether any item at all is in the disk drive +-- +-- @tparam string name The name of the disk drive. +-- @treturn boolean If something is in the disk drive. +-- @usage disk.isPresent(false) +function isPresent(name) + if isDrive(name) then + return peripheral.call(name, "isDiskPresent") end return false end -function getLabel( name ) - if isDrive( name ) then - return peripheral.call( name, "getDiskLabel" ) +--- Get the label of the floppy disk, record, or other media within the given +-- disk drive. +-- +-- If there is a computer or turtle within the drive, this will set the label as +-- read by `os.getComputerLabel`. +-- +-- @tparam string name The name of the disk drive. +-- @treturn string|nil The name of the current media, or `nil` if the drive is +-- not present or empty. +-- @see disk.setLabel +function getLabel(name) + if isDrive(name) then + return peripheral.call(name, "getDiskLabel") end return nil end -function setLabel( name, label ) - if isDrive( name ) then - peripheral.call( name, "setDiskLabel", label ) +--- Set the label of the floppy disk or other media +-- +-- @tparam string name The name of the disk drive. +-- @tparam string|nil label The new label of the disk +function setLabel(name, label) + if isDrive(name) then + peripheral.call(name, "setDiskLabel", label) end end -function hasData( name ) - if isDrive( name ) then - return peripheral.call( name, "hasData" ) +--- Check whether the current disk provides a mount. +-- +-- This will return true for disks and computers, but not records. +-- +-- @tparam string name The name of the disk drive. +-- @treturn boolean If the disk is present and provides a mount. +-- @see disk.getMountPath +function hasData(name) + if isDrive(name) then + return peripheral.call(name, "hasData") end return false end -function getMountPath( name ) - if isDrive( name ) then - return peripheral.call( name, "getMountPath" ) +--- Find the directory name on the local computer where the contents of the +-- current floppy disk (or other mount) can be found. +-- +-- @tparam string name The name of the disk drive. +-- @treturn string|nil The mount's directory, or `nil` if the drive does not +-- contain a floppy or computer. +-- @see disk.hasData +function getMountPath(name) + if isDrive(name) then + return peripheral.call(name, "getMountPath") end return nil end -function hasAudio( name ) - if isDrive( name ) then - return peripheral.call( name, "hasAudio" ) +--- Whether the current disk is a [music disk][disk] as opposed to a floppy disk +-- or other item. +-- +-- If this returns true, you will can @{disk.playAudio|play} the record. +-- +-- [disk]: https://minecraft.gamepedia.com/Music_Disc +-- +-- @tparam string name The name of the disk drive. +-- @treturn boolean If the disk is present and has audio saved on it. +function hasAudio(name) + if isDrive(name) then + return peripheral.call(name, "hasAudio") end return false end -function getAudioTitle( name ) - if isDrive( name ) then - return peripheral.call( name, "getAudioTitle" ) +--- Get the title of the audio track from the music record in the drive. +-- +-- This generally returns the same as @{disk.getLabel} for records. +-- +-- @tparam string name The name of the disk drive. +-- @treturn string|false|nil The track title, `false` if there is not a music +-- record in the drive or `nil` if no drive is present. +function getAudioTitle(name) + if isDrive(name) then + return peripheral.call(name, "getAudioTitle") end return nil end -function playAudio( name ) - if isDrive( name ) then - peripheral.call( name, "playAudio" ) +--- Starts playing the music record in the drive. +-- +-- If any record is already playing on any disk drive, it stops before the +-- target drive starts playing. The record stops when it reaches the end of the +-- track, when it is removed from the drive, when @{disk.stopAudio} is called, or +-- when another record is started. +-- +-- @tparam string name The name of the disk drive. +-- @usage disk.playAudio("bottom") +function playAudio(name) + if isDrive(name) then + peripheral.call(name, "playAudio") end end -function stopAudio( name ) +--- Stops the music record in the drive from playing, if it was started with +-- @{disk.playAudio}. +-- +-- @tparam string name The name o the disk drive. +function stopAudio(name) if not name then - for _, sName in ipairs( peripheral.getNames() ) do - stopAudio( sName ) + for _, sName in ipairs(peripheral.getNames()) do + stopAudio(sName) end else - if isDrive( name ) then - peripheral.call( name, "stopAudio" ) + if isDrive(name) then + peripheral.call(name, "stopAudio") end end end -function eject( name ) - if isDrive( name ) then - peripheral.call( name, "ejectDisk" ) +--- Ejects any item currently in the drive, spilling it into the world as a loose item. +-- +-- @tparam string name The name of the disk drive. +-- @usage disk.eject("bottom") +function eject(name) + if isDrive(name) then + peripheral.call(name, "ejectDisk") end end -function getID( name ) - if isDrive( name ) then - return peripheral.call( name, "getDiskID" ) +--- Returns a number which uniquely identifies the disk in the drive. +-- +-- Note, unlike @{disk.getLabel}, this does not return anything for other media, +-- such as computers or turtles. +-- +-- @tparam string name The name of the disk drive. +-- @treturn string|nil The disk ID, or `nil` if the drive does not contain a floppy disk. +function getID(name) + if isDrive(name) then + return peripheral.call(name, "getDiskID") end return nil end - diff --git a/src/main/resources/data/computercraft/lua/rom/apis/gps.lua b/src/main/resources/data/computercraft/lua/rom/apis/gps.lua index 79b192494..3be8906a5 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/gps.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/gps.lua @@ -1,21 +1,46 @@ +--- The GPS API provides a method for turtles and computers to retrieve their +-- own locations. +-- +-- It broadcasts a PING message over @{rednet} and wait for responses. In order +-- for this system to work, there must be at least 4 computers used as gps hosts +-- which will respond and allow trilateration. Three of these hosts should be in +-- a plane, and the fourth should be either above or below the other three. The +-- three in a plane should not be in a line with each other. You can set up +-- hosts using the gps program. +-- +-- **Note**: When entering in the coordinates for the host you need to put in +-- the `x`, `y`, and `z` coordinates of the computer, not the modem, as all +-- rednet distances are measured from the block the computer is in. +-- +-- Also note that you may choose which axes x, y, or z refers to - so long as +-- your systems have the same definition as any GPS servers that're in range, it +-- works just the same. For example, you might build a GPS cluster according to +-- [this tutorial][1], using z to account for height, or you might use y to +-- account for height in the way that Minecraft's debug screen displays. +-- +-- [1]: http://www.computercraft.info/forums2/index.php?/topic/3088-how-to-guide-gps-global-position-system/ +-- +-- @module gps + local expect = dofile("rom/modules/main/cc/expect.lua").expect +--- The channel which GPS requests and responses are broadcast on. CHANNEL_GPS = 65534 -local function trilaterate( A, B, C ) +local function trilaterate(A, B, C) local a2b = B.vPosition - A.vPosition local a2c = C.vPosition - A.vPosition - if math.abs( a2b:normalize():dot( a2c:normalize() ) ) > 0.999 then + if math.abs(a2b:normalize():dot(a2c:normalize())) > 0.999 then return nil end local d = a2b:length() local ex = a2b:normalize( ) - local i = ex:dot( a2c ) + local i = ex:dot(a2c) local ey = (a2c - ex * i):normalize() - local j = ey:dot( a2c ) - local ez = ex:cross( ey ) + local j = ey:dot(a2c) + local ez = ex:cross(ey) local r1 = A.nDistance local r2 = B.nDistance @@ -28,35 +53,44 @@ local function trilaterate( A, B, C ) local zSquared = r1 * r1 - x * x - y * y if zSquared > 0 then - local z = math.sqrt( zSquared ) + local z = math.sqrt(zSquared) local result1 = result + ez * z local result2 = result - ez * z - local rounded1, rounded2 = result1:round( 0.01 ), result2:round( 0.01 ) + local rounded1, rounded2 = result1:round(0.01), result2:round(0.01) if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then return rounded1, rounded2 else return rounded1 end end - return result:round( 0.01 ) + return result:round(0.01) end -local function narrow( p1, p2, fix ) - local dist1 = math.abs( (p1 - fix.vPosition):length() - fix.nDistance ) - local dist2 = math.abs( (p2 - fix.vPosition):length() - fix.nDistance ) +local function narrow(p1, p2, fix) + local dist1 = math.abs((p1 - fix.vPosition):length() - fix.nDistance) + local dist2 = math.abs((p2 - fix.vPosition):length() - fix.nDistance) if math.abs(dist1 - dist2) < 0.01 then return p1, p2 elseif dist1 < dist2 then - return p1:round( 0.01 ) + return p1:round(0.01) else - return p2:round( 0.01 ) + return p2:round(0.01) end end -function locate( _nTimeout, _bDebug ) +--- Tries to retrieve the computer or turtles own location. +-- +-- @tparam[opt] number timeout The maximum time taken to establish our +-- position. Defaults to 2 seconds if not specified. +-- @tparam[opt] boolean debug Print debugging messages +-- @treturn[1] number This computer's `x` position. +-- @treturn[1] number This computer's `y` position. +-- @treturn[1] number This computer's `z` position. +-- @treturn[2] nil If the position could not be established. +function locate(_nTimeout, _bDebug) expect(1, _nTimeout, "number", "nil") expect(2, _bDebug, "boolean", "nil") -- Let command computers use their magic fourth-wall-breaking special abilities @@ -66,8 +100,8 @@ function locate( _nTimeout, _bDebug ) -- Find a modem local sModemSide = nil - for _, sSide in ipairs( rs.getSides() ) do - if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then + for _, sSide in ipairs(rs.getSides()) do + if peripheral.getType(sSide) == "modem" and peripheral.call(sSide, "isWireless") then sModemSide = sSide break end @@ -75,30 +109,30 @@ function locate( _nTimeout, _bDebug ) if sModemSide == nil then if _bDebug then - print( "No wireless modem attached" ) + print("No wireless modem attached") end return nil end if _bDebug then - print( "Finding position..." ) + print("Finding position...") end -- Open GPS channel to listen for ping responses - local modem = peripheral.wrap( sModemSide ) + local modem = peripheral.wrap(sModemSide) local bCloseChannel = false - if not modem.isOpen( CHANNEL_GPS ) then - modem.open( CHANNEL_GPS ) + if not modem.isOpen(CHANNEL_GPS) then + modem.open(CHANNEL_GPS) bCloseChannel = true end -- Send a ping to listening GPS hosts - modem.transmit( CHANNEL_GPS, CHANNEL_GPS, "PING" ) + modem.transmit(CHANNEL_GPS, CHANNEL_GPS, "PING") -- Wait for the responses local tFixes = {} local pos1, pos2 = nil, nil - local timeout = os.startTimer( _nTimeout or 2 ) + local timeout = os.startTimer(_nTimeout or 2) while true do local e, p1, p2, p3, p4, p5 = os.pullEvent() if e == "modem_message" then @@ -107,19 +141,19 @@ function locate( _nTimeout, _bDebug ) if sSide == sModemSide and sChannel == CHANNEL_GPS and sReplyChannel == CHANNEL_GPS and nDistance then -- Received the correct message from the correct modem: use it to determine position if type(tMessage) == "table" and #tMessage == 3 and tonumber(tMessage[1]) and tonumber(tMessage[2]) and tonumber(tMessage[3]) then - local tFix = { vPosition = vector.new( tMessage[1], tMessage[2], tMessage[3] ), nDistance = nDistance } + local tFix = { vPosition = vector.new(tMessage[1], tMessage[2], tMessage[3]), nDistance = nDistance } if _bDebug then - print( tFix.nDistance .. " metres from " .. tostring( tFix.vPosition ) ) + print(tFix.nDistance .. " metres from " .. tostring(tFix.vPosition)) end if tFix.nDistance == 0 then pos1, pos2 = tFix.vPosition, nil else - table.insert( tFixes, tFix ) + table.insert(tFixes, tFix) if #tFixes >= 3 then if not pos1 then - pos1, pos2 = trilaterate( tFixes[1], tFixes[2], tFixes[#tFixes] ) + pos1, pos2 = trilaterate(tFixes[1], tFixes[2], tFixes[#tFixes]) else - pos1, pos2 = narrow( pos1, pos2, tFixes[#tFixes] ) + pos1, pos2 = narrow(pos1, pos2, tFixes[#tFixes]) end end end @@ -141,24 +175,24 @@ function locate( _nTimeout, _bDebug ) -- Close the channel, if we opened one if bCloseChannel then - modem.close( CHANNEL_GPS ) + modem.close(CHANNEL_GPS) end -- Return the response if pos1 and pos2 then if _bDebug then - print( "Ambiguous position" ) - print( "Could be " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z .. " or " .. pos2.x .. "," .. pos2.y .. "," .. pos2.z ) + print("Ambiguous position") + print("Could be " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z .. " or " .. pos2.x .. "," .. pos2.y .. "," .. pos2.z) end return nil elseif pos1 then if _bDebug then - print( "Position is " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z ) + print("Position is " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z) end return pos1.x, pos1.y, pos1.z else if _bDebug then - print( "Could not determine position" ) + print("Could not determine position") end return nil end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/help.lua b/src/main/resources/data/computercraft/lua/rom/apis/help.lua index ded20f2f3..438af474f 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/help.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/help.lua @@ -1,24 +1,46 @@ +--- Provides an API to read help files. +-- +-- @module help + local expect = dofile("rom/modules/main/cc/expect.lua").expect local sPath = "/rom/help" +--- Returns a colon-separated list of directories where help files are searched +-- for. All directories are absolute. +-- +-- @treturn string The current help search path, separated by colons. +-- @see help.setPath function path() return sPath end -function setPath( _sPath ) +--- Sets the colon-seperated list of directories where help files are searched +-- for to `newPath` +-- +-- @tparam string newPath The new path to use. +-- @usage help.setPath( "/disk/help/" ) +-- @usage help.setPath( help.path() .. ":/myfolder/help/" ) +-- @see help.path +function setPath(_sPath) expect(1, _sPath, "string") sPath = _sPath end -function lookup( _sTopic ) +--- Returns the location of the help file for the given topic. +-- +-- @tparam string topic The topic to find +-- @treturn string|nil The path to the given topic's help file, or `nil` if it +-- cannot be found. +-- @usage print(help.lookup("disk")) +function lookup(_sTopic) expect(1, _sTopic, "string") -- Look on the path variable for sPath in string.gmatch(sPath, "[^:]+") do - sPath = fs.combine( sPath, _sTopic ) - if fs.exists( sPath ) and not fs.isDir( sPath ) then + sPath = fs.combine(sPath, _sTopic) + if fs.exists(sPath) and not fs.isDir(sPath) then return sPath - elseif fs.exists( sPath .. ".txt" ) and not fs.isDir( sPath .. ".txt" ) then + elseif fs.exists(sPath .. ".txt") and not fs.isDir(sPath .. ".txt") then return sPath .. ".txt" end end @@ -27,23 +49,26 @@ function lookup( _sTopic ) return nil end +--- Returns a list of topics that can be looked up and/or displayed. +-- +-- @treturn table A list of topics in alphabetical order. function topics() -- Add index local tItems = { - [ "index" ] = true, + ["index"] = true, } -- Add topics from the path for sPath in string.gmatch(sPath, "[^:]+") do - if fs.isDir( sPath ) then - local tList = fs.list( sPath ) - for _, sFile in pairs( tList ) do - if string.sub( sFile, 1, 1 ) ~= "." then - if not fs.isDir( fs.combine( sPath, sFile ) ) then + if fs.isDir(sPath) then + local tList = fs.list(sPath) + for _, sFile in pairs(tList) do + if string.sub(sFile, 1, 1) ~= "." then + if not fs.isDir(fs.combine(sPath, sFile)) then if #sFile > 4 and sFile:sub(-4) == ".txt" then sFile = sFile:sub(1, -5) end - tItems[ sFile ] = true + tItems[sFile] = true end end end @@ -52,21 +77,26 @@ function topics() -- Sort and return local tItemList = {} - for sItem in pairs( tItems ) do - table.insert( tItemList, sItem ) + for sItem in pairs(tItems) do + table.insert(tItemList, sItem) end - table.sort( tItemList ) + table.sort(tItemList) return tItemList end -function completeTopic( sText ) +--- Returns a list of topic endings that match the prefix. Can be used with +-- `read` to allow input of a help topic. +-- +-- @tparam string prefix The prefix to match +-- @treturn table A list of matching topics. +function completeTopic(sText) expect(1, sText, "string") local tTopics = topics() local tResults = {} for n = 1, #tTopics do local sTopic = tTopics[n] - if #sTopic > #sText and string.sub( sTopic, 1, #sText ) == sText then - table.insert( tResults, string.sub( sTopic, #sText + 1 ) ) + if #sTopic > #sText and string.sub(sTopic, 1, #sText) == sText then + table.insert(tResults, string.sub(sTopic, #sText + 1)) end end return tResults diff --git a/src/main/resources/data/computercraft/lua/rom/apis/io.lua b/src/main/resources/data/computercraft/lua/rom/apis/io.lua index 3cf28c80b..8079e022f 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/io.lua @@ -1,6 +1,10 @@ --- Definition for the IO API +--- Emulates Lua's standard [io library][io]. +-- +-- [io]: https://www.lua.org/manual/5.1/manual.html#5.7 +-- +-- @module io -local expect, typeOf = dofile("rom/modules/main/cc/expect.lua").expect, _G.type +local expect, type_of = dofile("rom/modules/main/cc/expect.lua").expect, _G.type --- If we return nil then close the file, as we've reached the end. -- We use this weird wrapper function as we wish to preserve the varargs @@ -9,6 +13,9 @@ local function checkResult(handle, ...) return ... end +--- A file handle which can be read or written to. +-- +-- @type Handle local handleMetatable handleMetatable = { __name = "FILE*", @@ -20,10 +27,17 @@ handleMetatable = { return "file (" .. hash .. ")" end end, + __index = { + --- Close this file handle, freeing any resources it uses. + -- + -- @treturn[1] true If this handle was successfully closed. + -- @treturn[2] nil If this file handle could not be closed. + -- @treturn[2] string The reason it could not be closed. + -- @throws If this handle was already closed. close = function(self) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -36,18 +50,24 @@ handleMetatable = { return nil, "attempt to close standard stream" end end, + + --- Flush any buffered output, forcing it to be written to the file + -- + -- @throws If the handle has been closed flush = function(self) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end local handle = self._handle if handle.flush then handle.flush() end + return true end, + lines = function(self, ...) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -57,9 +77,10 @@ handleMetatable = { local args = table.pack(...) return function() return checkResult(self, self:read(table.unpack(args, 1, args.n))) end end, + read = function(self, ...) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -71,9 +92,9 @@ handleMetatable = { for i = 1, n do local arg = select(i, ...) local res - if typeOf(arg) == "number" then + if type_of(arg) == "number" then if handle.read then res = handle.read(arg) end - elseif typeOf(arg) == "string" then + elseif type_of(arg) == "string" then local format = arg:gsub("^%*", ""):sub(1, 1) if format == "l" then @@ -88,7 +109,7 @@ handleMetatable = { error("bad argument #" .. i .. " (invalid format)", 2) end else - error("bad argument #" .. i .. " (expected string, got " .. typeOf(arg) .. ")", 2) + error("bad argument #" .. i .. " (expected string, got " .. type_of(arg) .. ")", 2) end output[i] = res @@ -99,9 +120,10 @@ handleMetatable = { if n == 0 and handle.readLine then return handle.readLine() end return table.unpack(output, 1, n) end, + seek = function(self, whence, offset) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -111,10 +133,18 @@ handleMetatable = { -- It's a tail call, so error positions are preserved return handle.seek(whence, offset) end, + setvbuf = function(self, mode, size) end, + + --- Write one or more values to the file + -- + -- @tparam string|number ... The values to write. + -- @treturn[1] Handle The current file, allowing chained calls. + -- @treturn[2] nil If the file could not be written to. + -- @treturn[2] string The error message which occurred while writing. write = function(self, ...) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -156,41 +186,88 @@ local defaultError = setmetatable({ local currentInput = defaultInput local currentOutput = defaultOutput +--- A file handle representing the "standard input". Reading from this +-- file will prompt the user for input. stdin = defaultInput + +--- A file handle representing the "standard output". Writing to this +-- file will display the written text to the screen. stdout = defaultOutput + +--- A file handle representing the "standard error" stream. +-- +-- One may use this to display error messages, writing to it will display +-- them on the terminal. stderr = defaultError -function close(_file) - if _file == nil then return currentOutput:close() end +--- Closes the provided file handle. +-- +-- @tparam[opt] Handle file The file handle to close, defaults to the +-- current output file. +-- +-- @see Handle:close +-- @see io.output +function close(file) + if file == nil then return currentOutput:close() end - if typeOf(_file) ~= "table" or getmetatable(_file) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(_file) .. ")", 2) + if type_of(file) ~= "table" or getmetatable(file) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(file) .. ")", 2) end - return _file:close() + return file:close() end +--- Flushes the current output file. +-- +-- @see Handle:flush +-- @see io.output function flush() return currentOutput:flush() end -function input(_arg) - if typeOf(_arg) == "string" then - local res, err = open(_arg, "rb") +--- Get or set the current input file. +-- +-- @tparam[opt] Handle|string file The new input file, either as a file path or pre-existing handle. +-- @treturn Handle The current input file. +-- @throws If the provided filename cannot be opened for reading. +function input(file) + if type_of(file) == "string" then + local res, err = open(file, "rb") if not res then error(err, 2) end currentInput = res - elseif typeOf(_arg) == "table" and getmetatable(_arg) == handleMetatable then - currentInput = _arg - elseif _arg ~= nil then - error("bad argument #1 (FILE expected, got " .. typeOf(_arg) .. ")", 2) + elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then + currentInput = file + elseif file ~= nil then + error("bad fileument #1 (FILE expected, got " .. type_of(file) .. ")", 2) end return currentInput end -function lines(_sFileName) - expect(1, _sFileName, "string", "nil") - if _sFileName then - local ok, err = open(_sFileName, "rb") +--- Opens the given file name in read mode and returns an iterator that, +-- each time it is called, returns a new line from the file. +-- +-- This can be used in a for loop to iterate over all lines of a file: +-- +-- ```lua +-- for line in io.lines(filename) do print(line) end +-- ``` +-- +-- Once the end of the file has been reached, @{nil} will be +-- returned. The file is automatically closed. +-- +-- If no file name is given, the @{io.input|current input} will be used +-- instead. In this case, the handle is not used. +-- +-- @tparam[opt] string filename The name of the file to extract lines from +-- @treturn function():string|nil The line iterator. +-- @throws If the file cannot be opened for reading +-- +-- @see Handle:lines +-- @see io.input +function lines(filename) + expect(1, filename, "string", "nil") + if filename then + local ok, err = open(filename, "rb") if not ok then error(err, 2) end -- We set this magic flag to mark this file as being opened by io.lines and so should be @@ -202,38 +279,72 @@ function lines(_sFileName) end end -function open(_sPath, _sMode) - expect(1, _sPath, "string") - expect(2, _sMode, "string", "nil") +--- Open a file with the given mode, either returning a new file handle +-- or @{nil}, plus an error message. +-- +-- The `mode` string can be any of the following: +-- - **"r"**: Read mode +-- - **"w"**: Write mode +-- - **"w"**: Append mode +-- +-- The mode may also have a `b` at the end, which opens the file in "binary +-- mode". This allows you to read binary files, as well as seek within a file. +-- +-- @tparam string filename The name of the file to open. +-- @tparam[opt] string mode The mode to open the file with. This defaults to `rb`. +-- @treturn[1] Handle The opened file. +-- @treturn[2] nil In case of an error. +-- @treturn[2] string The reason the file could not be opened. +function open(filename, mode) + expect(1, filename, "string") + expect(2, mode, "string", "nil") - local sMode = _sMode and _sMode:gsub("%+", "") or "rb" - local file, err = fs.open(_sPath, sMode) + local sMode = mode and mode:gsub("%+", "") or "rb" + local file, err = fs.open(filename, sMode) if not file then return nil, err end return setmetatable({ _handle = file }, handleMetatable) end -function output(_arg) - if typeOf(_arg) == "string" then - local res, err = open(_arg, "w") +--- Get or set the current output file. +-- +-- @tparam[opt] Handle|string file The new output file, either as a file path or pre-existing handle. +-- @treturn Handle The current output file. +-- @throws If the provided filename cannot be opened for writing. +function output(file) + if type_of(file) == "string" then + local res, err = open(file, "w") if not res then error(err, 2) end currentOutput = res - elseif typeOf(_arg) == "table" and getmetatable(_arg) == handleMetatable then - currentOutput = _arg - elseif _arg ~= nil then - error("bad argument #1 (FILE expected, got " .. typeOf(_arg) .. ")", 2) + elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then + currentOutput = file + elseif file ~= nil then + error("bad argument #1 (FILE expected, got " .. type_of(file) .. ")", 2) end return currentOutput end +--- Read from the currently opened input file. +-- +-- This is equivalent to `io.input():read(...)`. See @{Handle:read|the +-- documentation} there for full details. +-- +-- @tparam string ... The formats to read, defaulting to a whole line. +-- @treturn (string|nil)... The data read, or @{nil} if nothing can be read. function read(...) return currentInput:read(...) end -function type(handle) - if typeOf(handle) == "table" and getmetatable(handle) == handleMetatable then - if handle._closed then +--- Checks whether `handle` is a given file handle, and determine if it is open +-- or not. +-- +-- @param obj The value to check +-- @treturn string|nil `"file"` if this is an open file, `"closed file"` if it +-- is a closed file handle, or `nil` if not a file handle. +function type(obj) + if type_of(obj) == "table" and getmetatable(obj) == handleMetatable then + if obj._closed then return "closed file" else return "file" @@ -242,6 +353,12 @@ function type(handle) return nil end +--- Write to the currently opened output file. +-- +-- This is equivalent to `io.output():write(...)`. See @{Handle:write|the +-- documentation} there for full details. +-- +-- @tparam string ... The strings to write function write(...) return currentOutput:write(...) end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/keys.lua b/src/main/resources/data/computercraft/lua/rom/apis/keys.lua index 06dc1c6d1..90f877aa5 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/keys.lua @@ -1,12 +1,11 @@ ---- Key codes for ComputerCraft +--- The Keys API provides a table of numerical codes corresponding to keyboard +-- keys, suitable for decoding key events. -- --- This is derived from the GLFW list of key codes, and mostly created via --- a couple of regexes. +-- These values are not guaranteed to remain the same between versions. It is +-- recommended that you use the constants provided by this file, rather than +-- the underlying numerical values. -- --- Note that this is technically incompatible with previous versions of CC, as --- they relied on Minecraft's character mappings. However, if CC emulators have --- taught me anything, it's that emulating LWJGL's weird key handling is nigh-on --- impossible. +-- @module keys local expect = dofile("rom/modules/main/cc/expect.lua").expect @@ -126,22 +125,27 @@ tKeys[341] = 'leftCtrl' tKeys[342] = 'leftAlt' -- tKeys[343] = 'leftSuper' tKeys[344] = 'rightShift' -tKeys[345] = 'rightControl' +tKeys[345] = 'rightCtrl' tKeys[346] = 'rightAlt' -- tKeys[347] = 'rightSuper' -- tKeys[348] = 'menu' local keys = _ENV -for nKey, sKey in pairs( tKeys ) do +for nKey, sKey in pairs(tKeys) do keys[sKey] = nKey end -- Alias some keys for ease-of-use and backwards compatibility -keys["return"] = keys.enter -keys.scollLock = keys.scrollLock -keys.cimcumflex = keys.circumflex +keys["return"] = keys.enter --- @local +keys.scollLock = keys.scrollLock --- @local +keys.cimcumflex = keys.circumflex --- @local -function getName( _nKey ) +--- Translates a numerical key code to a human-readable name. The human-readable +-- name is one of the constants in the keys API. +-- +-- @tparam number code The key code to look up. +-- @treturn string|nil The name of the key, or `nil` if not a valid key code. +function getName(_nKey) expect(1, _nKey, "number") - return tKeys[ _nKey ] + return tKeys[_nKey] end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua index d725367d0..1af17ee6c 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua @@ -1,75 +1,117 @@ +--- An API for advanced systems which can draw pixels and lines, load and draw +-- image files. You can use the `colors` API for easier color manipulation. +-- +-- @module paintutils + local expect = dofile("rom/modules/main/cc/expect.lua").expect -local function drawPixelInternal( xPos, yPos ) - term.setCursorPos( xPos, yPos ) +local function drawPixelInternal(xPos, yPos) + term.setCursorPos(xPos, yPos) term.write(" ") end local tColourLookup = {} for n = 1, 16 do - tColourLookup[ string.byte( "0123456789abcdef", n, n ) ] = 2 ^ (n - 1) + tColourLookup[string.byte("0123456789abcdef", n, n)] = 2 ^ (n - 1) end -local function parseLine( tImageArg, sLine ) +local function parseLine(tImageArg, sLine) local tLine = {} for x = 1, sLine:len() do - tLine[x] = tColourLookup[ string.byte(sLine, x, x) ] or 0 + tLine[x] = tColourLookup[string.byte(sLine, x, x)] or 0 end - table.insert( tImageArg, tLine ) + table.insert(tImageArg, tLine) end -function parseImage( sRawData ) - expect(1, sRawData, "string") +--- Parses an image from a multi-line string +-- +-- @tparam string image The string containing the raw-image data. +-- @treturn table The parsed image data, suitable for use with +-- @{paintutils.drawImage}. +function parseImage(image) + expect(1, image, "string") local tImage = {} - for sLine in ( sRawData .. "\n" ):gmatch( "(.-)\n" ) do -- read each line like original file handling did - parseLine( tImage, sLine ) + for sLine in (image .. "\n"):gmatch("(.-)\n") do + parseLine(tImage, sLine) end return tImage end -function loadImage( sPath ) - expect(1, sPath, "string") +--- Loads an image from a file. +-- +-- You can create a file suitable for being loaded using the `paint` program. +-- +-- @tparam string path The file to load. +-- +-- @treturn table|nil The parsed image data, suitable for use with +-- @{paintutils.drawImage}, or `nil` if the file does not exist. +function loadImage(path) + expect(1, path, "string") - if fs.exists( sPath ) then - local file = io.open( sPath, "r" ) + if fs.exists(path) then + local file = io.open(path, "r") local sContent = file:read("*a") file:close() - return parseImage( sContent ) -- delegate image parse to parseImage + return parseImage(sContent) end return nil end -function drawPixel( xPos, yPos, nColour ) +--- Draws a single pixel to the current term at the specified position. +-- +-- Be warned, this may change the position of the cursor and the current +-- background colour. You should not expect either to be preserved. +-- +-- @tparam number xPos The x position to draw at, where 1 is the far left. +-- @tparam number yPos The y position to draw at, where 1 is the very top. +-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be +-- the current background colour if not specified. +function drawPixel(xPos, yPos, colour) expect(1, xPos, "number") expect(2, yPos, "number") - expect(3, nColour, "number", "nil") - if nColour then - term.setBackgroundColor( nColour ) + expect(3, colour, "number", "nil") + + if type(xPos) ~= "number" then error("bad argument #1 (expected number, got " .. type(xPos) .. ")", 2) end + if type(yPos) ~= "number" then error("bad argument #2 (expected number, got " .. type(yPos) .. ")", 2) end + if colour ~= nil and type(colour) ~= "number" then error("bad argument #3 (expected number, got " .. type(colour) .. ")", 2) end + if colour then + term.setBackgroundColor(colour) end - return drawPixelInternal( xPos, yPos ) + return drawPixelInternal(xPos, yPos) end -function drawLine( startX, startY, endX, endY, nColour ) +--- Draws a straight line from the start to end position. +-- +-- Be warned, this may change the position of the cursor and the current +-- background colour. You should not expect either to be preserved. +-- +-- @tparam number startX The starting x position of the line. +-- @tparam number startY The starting y position of the line. +-- @tparam number endX The end x position of the line. +-- @tparam number endY The end y position of the line. +-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be +-- the current background colour if not specified. +function drawLine(startX, startY, endX, endY, colour) expect(1, startX, "number") expect(2, startY, "number") expect(3, endX, "number") expect(4, endY, "number") - expect(5, nColour, "number", "nil") + expect(5, colour, "number", "nil") startX = math.floor(startX) startY = math.floor(startY) endX = math.floor(endX) endY = math.floor(endY) - if nColour then - term.setBackgroundColor( nColour ) + if colour then + term.setBackgroundColor(colour) end if startX == endX and startY == endY then - drawPixelInternal( startX, startY ) + drawPixelInternal(startX, startY) return end - local minX = math.min( startX, endX ) + local minX = math.min(startX, endX) local maxX, minY, maxY if minX == startX then minY = startY @@ -90,7 +132,7 @@ function drawLine( startX, startY, endX, endY, nColour ) local y = minY local dy = yDiff / xDiff for x = minX, maxX do - drawPixelInternal( x, math.floor( y + 0.5 ) ) + drawPixelInternal(x, math.floor(y + 0.5)) y = y + dy end else @@ -98,19 +140,31 @@ function drawLine( startX, startY, endX, endY, nColour ) local dx = xDiff / yDiff if maxY >= minY then for y = minY, maxY do - drawPixelInternal( math.floor( x + 0.5 ), y ) + drawPixelInternal(math.floor(x + 0.5), y) x = x + dx end else for y = minY, maxY, -1 do - drawPixelInternal( math.floor( x + 0.5 ), y ) + drawPixelInternal(math.floor(x + 0.5), y) x = x - dx end end end end -function drawBox( startX, startY, endX, endY, nColour ) +--- Draws the outline of a box on the current term from the specified start +-- position to the specified end position. +-- +-- Be warned, this may change the position of the cursor and the current +-- background colour. You should not expect either to be preserved. +-- +-- @tparam number startX The starting x position of the line. +-- @tparam number startY The starting y position of the line. +-- @tparam number endX The end x position of the line. +-- @tparam number endY The end y position of the line. +-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be +-- the current background colour if not specified. +function drawBox(startX, startY, endX, endY, nColour) expect(1, startX, "number") expect(2, startY, "number") expect(3, endX, "number") @@ -123,14 +177,14 @@ function drawBox( startX, startY, endX, endY, nColour ) endY = math.floor(endY) if nColour then - term.setBackgroundColor( nColour ) + term.setBackgroundColor(nColour) end if startX == endX and startY == endY then - drawPixelInternal( startX, startY ) + drawPixelInternal(startX, startY) return end - local minX = math.min( startX, endX ) + local minX = math.min(startX, endX) local maxX, minY, maxY if minX == startX then minY = startY @@ -143,19 +197,30 @@ function drawBox( startX, startY, endX, endY, nColour ) end for x = minX, maxX do - drawPixelInternal( x, minY ) - drawPixelInternal( x, maxY ) + drawPixelInternal(x, minY) + drawPixelInternal(x, maxY) end if maxY - minY >= 2 then for y = minY + 1, maxY - 1 do - drawPixelInternal( minX, y ) - drawPixelInternal( maxX, y ) + drawPixelInternal(minX, y) + drawPixelInternal(maxX, y) end end end - -function drawFilledBox( startX, startY, endX, endY, nColour ) +--- Draws a filled box on the current term from the specified start position to +-- the specified end position. +-- +-- Be warned, this may change the position of the cursor and the current +-- background colour. You should not expect either to be preserved. +-- +-- @tparam number startX The starting x position of the line. +-- @tparam number startY The starting y position of the line. +-- @tparam number endX The end x position of the line. +-- @tparam number endY The end y position of the line. +-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be +-- the current background colour if not specified. +function drawFilledBox(startX, startY, endX, endY, nColour) expect(1, startX, "number") expect(2, startY, "number") expect(3, endX, "number") @@ -168,14 +233,14 @@ function drawFilledBox( startX, startY, endX, endY, nColour ) endY = math.floor(endY) if nColour then - term.setBackgroundColor( nColour ) + term.setBackgroundColor(nColour) end if startX == endX and startY == endY then - drawPixelInternal( startX, startY ) + drawPixelInternal(startX, startY) return end - local minX = math.min( startX, endX ) + local minX = math.min(startX, endX) local maxX, minY, maxY if minX == startX then minY = startY @@ -189,21 +254,26 @@ function drawFilledBox( startX, startY, endX, endY, nColour ) for x = minX, maxX do for y = minY, maxY do - drawPixelInternal( x, y ) + drawPixelInternal(x, y) end end end -function drawImage( tImage, xPos, yPos ) - expect(1, tImage, "table") +--- Draw an image loaded by @{paintutils.parseImage} or @{paintutils.loadImage}. +-- +-- @tparam table image The parsed image data. +-- @tparam number xPos The x position to start drawing at. +-- @tparam number xPos The y position to start drawing at. +function drawImage(image, xPos, yPos) + expect(1, image, "table") expect(2, xPos, "number") expect(3, yPos, "number") - for y = 1, #tImage do - local tLine = tImage[y] + for y = 1, #image do + local tLine = image[y] for x = 1, #tLine do if tLine[x] > 0 then - term.setBackgroundColor( tLine[x] ) - drawPixelInternal( x + xPos - 1, y + yPos - 1 ) + term.setBackgroundColor(tLine[x]) + drawPixelInternal(x + xPos - 1, y + yPos - 1) end end end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/parallel.lua b/src/main/resources/data/computercraft/lua/rom/apis/parallel.lua index 43b832c8b..c787eff41 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/parallel.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/parallel.lua @@ -1,11 +1,26 @@ +--- Provides a simple implementation of multitasking. +-- +-- Functions are not actually executed simultaniously, but rather this API will +-- automatically switch between them whenever they yield (eg whenever they call +-- @{coroutine.yield}, or functions that call that - eg `os.pullEvent` - or +-- functions that call that, etc - basically, anything that causes the function +-- to "pause"). +-- +-- Each function executed in "parallel" gets its own copy of the event queue, +-- and so "event consuming" functions (again, mostly anything that causes the +-- script to pause - eg `sleep`, `rednet.receive`, most of the `turtle` API, +-- etc) can safely be used in one without affecting the event queue accessed by +-- the other. +-- +-- @module parallel -local function create( ... ) +local function create(...) local tFns = table.pack(...) local tCos = {} for i = 1, tFns.n, 1 do local fn = tFns[i] - if type( fn ) ~= "function" then - error( "bad argument #" .. i .. " (expected function, got " .. type( fn ) .. ")", 3 ) + if type(fn) ~= "function" then + error("bad argument #" .. i .. " (expected function, got " .. type(fn) .. ")", 3) end tCos[i] = coroutine.create(fn) @@ -14,7 +29,7 @@ local function create( ... ) return tCos end -local function runUntilLimit( _routines, _limit ) +local function runUntilLimit(_routines, _limit) local count = #_routines local living = count @@ -25,13 +40,13 @@ local function runUntilLimit( _routines, _limit ) local r = _routines[n] if r then if tFilters[r] == nil or tFilters[r] == eventData[1] or eventData[1] == "terminate" then - local ok, param = coroutine.resume( r, table.unpack( eventData, 1, eventData.n ) ) + local ok, param = coroutine.resume(r, table.unpack(eventData, 1, eventData.n)) if not ok then - error( param, 0 ) + error(param, 0) else tFilters[r] = param end - if coroutine.status( r ) == "dead" then + if coroutine.status(r) == "dead" then _routines[n] = nil living = living - 1 if living <= _limit then @@ -43,7 +58,7 @@ local function runUntilLimit( _routines, _limit ) end for n = 1, count do local r = _routines[n] - if r and coroutine.status( r ) == "dead" then + if r and coroutine.status(r) == "dead" then _routines[n] = nil living = living - 1 if living <= _limit then @@ -51,16 +66,26 @@ local function runUntilLimit( _routines, _limit ) end end end - eventData = table.pack( os.pullEventRaw() ) + eventData = table.pack(os.pullEventRaw()) end end -function waitForAny( ... ) - local routines = create( ... ) - return runUntilLimit( routines, #routines - 1 ) +--- Switches between execution of the functions, until any of them +-- finishes. If any of the functions errors, the message is propagated upwards +-- from the @{parallel.waitForAny} call. +-- +-- @tparam function ... The functions this task will run +function waitForAny(...) + local routines = create(...) + return runUntilLimit(routines, #routines - 1) end -function waitForAll( ... ) - local routines = create( ... ) - runUntilLimit( routines, 0 ) +--- Switches between execution of the functions, until all of them are +-- finished. If any of the functions errors, the message is propagated upwards +-- from the @{parallel.waitForAll} call. +-- +-- @tparam function ... The functions this task will run +function waitForAll(...) + local routines = create(...) + return runUntilLimit(routines, 0) end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua index a398d696f..53b849adc 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua @@ -1,110 +1,184 @@ +--- The Peripheral API is for interacting with peripherals connected to the +-- computer, such as the Disk Drive, the Advanced Monitor and Monitor. +-- +-- Each peripheral block has a name, either referring to the side the peripheral +-- can be found on, or a name on an adjacent wired network. +-- +-- If the peripheral is next to the computer, its side is either `front`, +-- `back`, `left`, `right`, `top` or `bottom`. If the peripheral is attached by +-- a cable, its side will follow the format `type_id`, for example `printer_0`. +-- +-- Peripheral functions are called *methods*, a term borrowed from Java. +-- +-- @module peripheral + local expect = dofile("rom/modules/main/cc/expect.lua").expect local native = peripheral +local sides = rs.getSides() +--- Provides a list of all peripherals available. +-- +-- If a device is located directly next to the system, then its name will be +-- listed as the side it is attached to. If a device is attached via a Wired +-- Modem, then it'll be reported according to its name on the wired network. +-- +-- @treturn table A list of the names of all attached peripherals. function getNames() - local tResults = {} - for _, sSide in ipairs( rs.getSides() ) do - if native.isPresent( sSide ) then - table.insert( tResults, sSide ) - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - local tRemote = native.call( sSide, "getNamesRemote" ) - for _, sName in ipairs( tRemote ) do - table.insert( tResults, sName ) + local results = {} + for n = 1, #sides do + local side = sides[n] + if native.isPresent(side) then + table.insert(results, side) + if native.getType(side) == "modem" and not native.call(side, "isWireless") then + local remote = native.call(side, "getNamesRemote") + for _, name in ipairs(remote) do + table.insert(results, name) end end end end - return tResults + return results end -function isPresent( _sSide ) - expect(1, _sSide, "string") - if native.isPresent( _sSide ) then +--- Determines if a peripheral is present with the given name. +-- +-- @tparam string name The side or network name that you want to check. +-- @treturn boolean If a peripheral is present with the given name. +-- @usage peripheral.isPresent("top") +-- @usage peripheral.isPresent("monitor_0") +function isPresent(name) + expect(1, name, "string") + if native.isPresent(name) then return true end - for _, sSide in ipairs( rs.getSides() ) do - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - if native.call( sSide, "isPresentRemote", _sSide ) then - return true - end + + for n = 1, #sides do + local side = sides[n] + if native.getType(side) == "modem" and not native.call(side, "isWireless") and + native.call(side, "isPresentRemote", name) + then + return true end end return false end -function getType( _sSide ) - expect(1, _sSide, "string") - if native.isPresent( _sSide ) then - return native.getType( _sSide ) +--- Get the type of the peripheral with the given name. +-- +-- @tparam string name The name of the peripheral to find. +-- @treturn string|nil The peripheral's type, or `nil` if it is not present. +function getType(name) + expect(1, name, "string") + if native.isPresent(name) then + return native.getType(name) end - for _, sSide in ipairs( rs.getSides() ) do - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - if native.call( sSide, "isPresentRemote", _sSide ) then - return native.call( sSide, "getTypeRemote", _sSide ) - end + for n = 1, #sides do + local side = sides[n] + if native.getType(side) == "modem" and not native.call(side, "isWireless") and + native.call(side, "isPresentRemote", name) + then + return native.call(side, "getTypeRemote", name) end end return nil end -function getMethods( _sSide ) - expect(1, _sSide, "string") - if native.isPresent( _sSide ) then - return native.getMethods( _sSide ) +--- Get all available methods for the peripheral with the given name. +-- +-- @tparam string name The name of the peripheral to find. +-- @treturn table|nil A list of methods provided by this peripheral, or `nil` if +-- it is not present. +function getMethods(name) + expect(1, name, "string") + if native.isPresent(name) then + return native.getMethods(name) end - for _, sSide in ipairs( rs.getSides() ) do - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - if native.call( sSide, "isPresentRemote", _sSide ) then - return native.call( sSide, "getMethodsRemote", _sSide ) - end + for n = 1, #sides do + local side = sides[n] + if native.getType(side) == "modem" and not native.call(side, "isWireless") and + native.call(side, "isPresentRemote", name) + then + return native.call(side, "getMethodsRemote", name) end end return nil end -function call( _sSide, _sMethod, ... ) - expect(1, _sSide, "string") - expect(2, _sMethod, "string") - if native.isPresent( _sSide ) then - return native.call( _sSide, _sMethod, ... ) +--- Call a method on the peripheral with the given name. +-- +-- @tparam string name The name of the peripheral to invoke the method on. +-- @tparam string method The name of the method +-- @param ... Additional arguments to pass to the method +-- @return The return values of the peripheral method. +-- +-- @usage Open the modem on the top of this computer. +-- +-- peripheral.call("top", "open", 1) +function call(name, method, ...) + expect(1, name, "string") + expect(2, method, "string") + if native.isPresent(name) then + return native.call(name, method, ...) end - for _, sSide in ipairs( rs.getSides() ) do - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - if native.call( sSide, "isPresentRemote", _sSide ) then - return native.call( sSide, "callRemote", _sSide, _sMethod, ... ) - end + + for n = 1, #sides do + local side = sides[n] + if native.getType(side) == "modem" and not native.call(side, "isWireless") and + native.call(side, "isPresentRemote", name) + then + return native.call(side, "callRemote", name, method, ...) end end return nil end -function wrap( _sSide ) - expect(1, _sSide, "string") - if peripheral.isPresent( _sSide ) then - local tMethods = peripheral.getMethods( _sSide ) - local tResult = {} - for _, sMethod in ipairs( tMethods ) do - tResult[sMethod] = function( ... ) - return peripheral.call( _sSide, sMethod, ... ) - end - end - return tResult +--- Get a table containing functions pointing to the peripheral's methods, which +-- can then be called as if using @{peripheral.call}. +-- +-- @tparam string name The name of the peripheral to wrap. +-- @treturn table|nil The table containing the peripheral's methods, or `nil` if +-- there is no peripheral present with the given name. +-- @usage peripheral.wrap("top").open(1) +function wrap(name) + expect(1, name, "string") + + local methods = peripheral.getMethods(name) + if not methods then + return nil end - return nil + + local result = {} + for _, method in ipairs(methods) do + result[method] = function(...) + return peripheral.call(name, method, ...) + end + end + return result end -function find( sType, fnFilter ) - expect(1, sType, "string") - expect(2, fnFilter, "function", "nil") - local tResults = {} - for _, sName in ipairs( peripheral.getNames() ) do - if peripheral.getType( sName ) == sType then - local wrapped = peripheral.wrap( sName ) - if fnFilter == nil or fnFilter( sName, wrapped ) then - table.insert( tResults, wrapped ) +--- Find all peripherals of a specific type, and return the +-- @{peripheral.wrap|wrapped} peripherals. +-- +-- @tparam string ty The type of peripheral to look for. +-- @tparam[opt] function(name:string, wrapped:table):boolean filter A +-- filter function, which takes the peripheral's name and wrapped table +-- and returns if it should be included in the result. +-- @treturn table... 0 or more wrapped peripherals matching the given filters. +-- @usage local monitors = { peripheral.find("monitor") } +-- @usage peripheral.find("modem", rednet.open) +function find(ty, filter) + expect(1, ty, "string") + expect(2, filter, "function", "nil") + + local results = {} + for _, name in ipairs(peripheral.getNames()) do + if peripheral.getType(name) == ty then + local wrapped = peripheral.wrap(name) + if filter == nil or filter(name, wrapped) then + table.insert(results, wrapped) end end end - return table.unpack( tResults ) + return table.unpack(results) end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua index d6bf5d668..ab68db4b6 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua @@ -1,51 +1,92 @@ +--- The Rednet API allows systems to communicate between each other without +-- using redstone. It serves as a wrapper for the modem API, offering ease of +-- functionality (particularly in regards to repeating signals) with some +-- expense of fine control. +-- +-- In order to send and receive data, a modem (either wired, wireless, or ender) +-- is required. The data reaches any possible destinations immediately after +-- sending it, but is range limited. +-- +-- Rednet also allows you to use a "protocol" - simple string names indicating +-- what messages are about. Receiving systems may filter messages according to +-- their protocols, thereby automatically ignoring incoming messages which don't +-- specify an identical string. It's also possible to @{rednet.lookup|lookup} +-- which systems in the area use certain protocols, hence making it easier to +-- determine where given messages should be sent in the first place. +-- +-- @module rednet + local expect = dofile("rom/modules/main/cc/expect.lua").expect +--- The channel used by the Rednet API to @{broadcast} messages. CHANNEL_BROADCAST = 65535 + +--- The channel used by the Rednet API to repeat messages. CHANNEL_REPEAT = 65533 local tReceivedMessages = {} local tReceivedMessageTimeouts = {} local tHostnames = {} -function open( sModem ) - expect(1, sModem, "string") - if peripheral.getType( sModem ) ~= "modem" then - error( "No such modem: " .. sModem, 2 ) +--- Opens a modem with the given @{peripheral} name, allowing it to send and +--- receive messages over rednet. +-- +-- This will open the modem on two channels: one which has the same +-- @{os.getComputerID|ID} as the computer, and another on +-- @{CHANNEL_BROADCAST|the broadcast channel}. +-- +-- @tparam string modem The name of the modem to open. +-- @throws If there is no such modem with the given name +function open(modem) + expect(1, modem, "string") + if peripheral.getType(modem) ~= "modem" then + error("No such modem: " .. modem, 2) end - peripheral.call( sModem, "open", os.getComputerID() ) - peripheral.call( sModem, "open", CHANNEL_BROADCAST ) + peripheral.call(modem, "open", os.getComputerID()) + peripheral.call(modem, "open", CHANNEL_BROADCAST) end -function close( sModem ) - expect(1, sModem, "string", "nil") - if sModem then +--- Close a modem with the given @{peripheral} name, meaning it can no longer +-- send and receive rednet messages. +-- +-- @tparam[opt] string modem The side the modem exists on. If not given, all +-- open modems will be closed. +-- @throws If there is no such modem with the given name +function close(modem) + expect(1, modem, "string", "nil") + if modem then -- Close a specific modem - if peripheral.getType( sModem ) ~= "modem" then - error( "No such modem: " .. sModem, 2 ) + if peripheral.getType(modem) ~= "modem" then + error("No such modem: " .. modem, 2) end - peripheral.call( sModem, "close", os.getComputerID() ) - peripheral.call( sModem, "close", CHANNEL_BROADCAST ) + peripheral.call(modem, "close", os.getComputerID()) + peripheral.call(modem, "close", CHANNEL_BROADCAST) else -- Close all modems - for _, sModem in ipairs( peripheral.getNames() ) do - if isOpen( sModem ) then - close( sModem ) + for _, modem in ipairs(peripheral.getNames()) do + if isOpen(modem) then + close(modem) end end end end -function isOpen( sModem ) - expect(1, sModem, "string", "nil") - if sModem then +--- Determine if rednet is currently open. +-- +-- @tparam[opt] string modem Which modem to check. If not given, all connected +-- modems will be checked. +-- @treturn boolean If the given modem is open. +function isOpen(modem) + expect(1, modem, "string", "nil") + if modem then -- Check if a specific modem is open - if peripheral.getType( sModem ) == "modem" then - return peripheral.call( sModem, "isOpen", os.getComputerID() ) and peripheral.call( sModem, "isOpen", CHANNEL_BROADCAST ) + if peripheral.getType(modem) == "modem" then + return peripheral.call(modem, "isOpen", os.getComputerID()) and peripheral.call(modem, "isOpen", CHANNEL_BROADCAST) end else -- Check if any modem is open - for _, sModem in ipairs( peripheral.getNames() ) do - if isOpen( sModem ) then + for _, modem in ipairs(peripheral.getNames()) do + if isOpen(modem) then return true end end @@ -53,15 +94,32 @@ function isOpen( sModem ) return false end -function send( nRecipient, message, sProtocol ) +--- Allows a computer or turtle with an attached modem to send a message +-- intended for a system with a specific ID. At least one such modem must first +-- be @{rednet.open|opened} before sending is possible. +-- +-- Assuming the target was in range and also had a correctly opened modem, it +-- may then use @{rednet.receive} to collect the message. +-- +-- @tparam number nRecipient The ID of the receiving computer. +-- @param message The message to send. This should not contain coroutines or +-- functions, as they will be converted to @{nil}. +-- @tparam[opt] string sProtocol The "protocol" to send this message under. When +-- using @{rednet.receive} one can filter to only receive messages sent under a +-- particular protocol. +-- @treturn boolean If this message was successfully sent (i.e. if rednet is +-- currently @{rednet.open|open}). Note, this does not guarantee the message was +-- actually _received_. +-- @see rednet.receive +function send(nRecipient, message, sProtocol) expect(1, nRecipient, "number") expect(3, sProtocol, "string", "nil") -- Generate a (probably) unique message ID -- We could do other things to guarantee uniqueness, but we really don't need to -- Store it to ensure we don't get our own messages back - local nMessageID = math.random( 1, 2147483647 ) - tReceivedMessages[ nMessageID ] = true - tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID + local nMessageID = math.random(1, 2147483647) + tReceivedMessages[nMessageID] = true + tReceivedMessageTimeouts[os.startTimer(30)] = nMessageID -- Create the message local nReplyChannel = os.getComputerID() @@ -75,14 +133,14 @@ function send( nRecipient, message, sProtocol ) local sent = false if nRecipient == os.getComputerID() then -- Loopback to ourselves - os.queueEvent( "rednet_message", nReplyChannel, message, sProtocol ) + os.queueEvent("rednet_message", nReplyChannel, message, sProtocol) sent = true else -- Send on all open modems, to the target and to repeaters - for _, sModem in ipairs( peripheral.getNames() ) do - if isOpen( sModem ) then - peripheral.call( sModem, "transmit", nRecipient, nReplyChannel, tMessage ) - peripheral.call( sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage ) + for _, sModem in ipairs(peripheral.getNames()) do + if isOpen(sModem) then + peripheral.call(sModem, "transmit", nRecipient, nReplyChannel, tMessage) + peripheral.call(sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage) sent = true end end @@ -91,12 +149,35 @@ function send( nRecipient, message, sProtocol ) return sent end -function broadcast( message, sProtocol ) +--- Broadcasts a string message over the predefined @{CHANNEL_BROADCAST} +-- channel. The message will be received by every device listening to rednet. +-- +-- @param message The message to send. This should not contain coroutines or +-- functions, as they will be converted to @{nil}. +-- @tparam[opt] string sProtocol The "protocol" to send this message under. When +-- using @{rednet.receive} one can filter to only receive messages sent under a +-- particular protocol. +-- @see rednet.receive +function broadcast(message, sProtocol) expect(2, sProtocol, "string", "nil") - send( CHANNEL_BROADCAST, message, sProtocol ) + send(CHANNEL_BROADCAST, message, sProtocol) end -function receive( sProtocolFilter, nTimeout ) +--- Wait for a rednet message to be received, or until `nTimeout` seconds have +-- elapsed. +-- +-- @tparam[opt] string sProtocolFilter The protocol the received message must be +-- sent with. If specified, any messages not sent under this protocol will be +-- discarded. +-- @tparam[opt] number nTimeout The number of seconds to wait if no message is +-- received. +-- @treturn[1] number The computer which sent this message +-- @return[1] The received message +-- @treturn[1] string|nil The protocol this message was sent under. +-- @treturn[2] nil If the timeout elapsed and no message was received. +-- @see rednet.broadcast +-- @see rednet.send +function receive(sProtocolFilter, nTimeout) -- The parameters used to be ( nTimeout ), detect this case for backwards compatibility if type(sProtocolFilter) == "number" and nTimeout == nil then sProtocolFilter, nTimeout = nil, sProtocolFilter @@ -108,7 +189,7 @@ function receive( sProtocolFilter, nTimeout ) local timer = nil local sFilter = nil if nTimeout then - timer = os.startTimer( nTimeout ) + timer = os.startTimer(nTimeout) sFilter = nil else sFilter = "rednet_message" @@ -116,7 +197,7 @@ function receive( sProtocolFilter, nTimeout ) -- Wait for events while true do - local sEvent, p1, p2, p3 = os.pullEvent( sFilter ) + local sEvent, p1, p2, p3 = os.pullEvent(sFilter) if sEvent == "rednet_message" then -- Return the first matching rednet_message local nSenderID, message, sProtocol = p1, p2, p3 @@ -132,26 +213,62 @@ function receive( sProtocolFilter, nTimeout ) end end -function host( sProtocol, sHostname ) +--- Register the system as "hosting" the desired protocol under the specified +-- name. If a rednet @{rednet.lookup|lookup} is performed for that protocol (and +-- maybe name) on the same network, the registered system will automatically +-- respond via a background process, hence providing the system performing the +-- lookup with its ID number. +-- +-- Multiple computers may not register themselves on the same network as having +-- the same names against the same protocols, and the title `localhost` is +-- specifically reserved. They may, however, share names as long as their hosted +-- protocols are different, or if they only join a given network after +-- "registering" themselves before doing so (eg while offline or part of a +-- different network). +-- +-- @tparam string sProtocol The protocol this computer provides. +-- @tparam string sHostname The name this protocol exposes for the given protocol. +-- @throws If trying to register a hostname which is reserved, or currently in use. +-- @see rednet.unhost +-- @see rednet.lookup +function host(sProtocol, sHostname) expect(1, sProtocol, "string") expect(2, sHostname, "string") if sHostname == "localhost" then - error( "Reserved hostname", 2 ) + error("Reserved hostname", 2) end - if tHostnames[ sProtocol ] ~= sHostname then - if lookup( sProtocol, sHostname ) ~= nil then - error( "Hostname in use", 2 ) + if tHostnames[sProtocol] ~= sHostname then + if lookup(sProtocol, sHostname) ~= nil then + error("Hostname in use", 2) end - tHostnames[ sProtocol ] = sHostname + tHostnames[sProtocol] = sHostname end end -function unhost( sProtocol ) +--- Stop @{rednet.host|hosting} a specific protocol, meaning it will no longer +--- respond to @{rednet.lookup} requests. +-- +-- @tparam string sProtocol The protocol to unregister your self from. +function unhost(sProtocol) expect(1, sProtocol, "string") - tHostnames[ sProtocol ] = nil + tHostnames[sProtocol] = nil end -function lookup( sProtocol, sHostname ) +--- Search the local rednet network for systems @{rednet.host|hosting} the +-- desired protocol and returns any computer IDs that respond as "registered" +-- against it. +-- +-- If a hostname is specified, only one ID will be returned (assuming an exact +-- match is found). +-- +-- @tparam string sProtocol The protocol to search for. +-- @tparam[opt] string sHostname The hostname to search for. +-- +-- @treturn[1] { number }|nil A list of computer IDs hosting the given +-- protocol, or @{nil} if none exist. +-- @treturn[2] number|nil The computer ID with the provided hostname and protocol, +-- or @{nil} if none exists. +function lookup(sProtocol, sHostname) expect(1, sProtocol, "string") expect(2, sHostname, "string", "nil") @@ -162,30 +279,30 @@ function lookup( sProtocol, sHostname ) end -- Check localhost first - if tHostnames[ sProtocol ] then + if tHostnames[sProtocol] then if sHostname == nil then - table.insert( tResults, os.getComputerID() ) - elseif sHostname == "localhost" or sHostname == tHostnames[ sProtocol ] then + table.insert(tResults, os.getComputerID()) + elseif sHostname == "localhost" or sHostname == tHostnames[sProtocol] then return os.getComputerID() end end if not isOpen() then if tResults then - return table.unpack( tResults ) + return table.unpack(tResults) end return nil end -- Broadcast a lookup packet - broadcast( { + broadcast({ sType = "lookup", sProtocol = sProtocol, sHostname = sHostname, - }, "dns" ) + }, "dns") -- Start a timer - local timer = os.startTimer( 2 ) + local timer = os.startTimer(2) -- Wait for events while true do @@ -196,7 +313,7 @@ function lookup( sProtocol, sHostname ) if sMessageProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup response" then if tMessage.sProtocol == sProtocol then if sHostname == nil then - table.insert( tResults, nSenderID ) + table.insert(tResults, nSenderID) elseif tMessage.sHostname == sHostname then return nSenderID end @@ -210,15 +327,17 @@ function lookup( sProtocol, sHostname ) end end if tResults then - return table.unpack( tResults ) + return table.unpack(tResults) end return nil end local bRunning = false + +--- @local function run() if bRunning then - error( "rednet is already running", 2 ) + error("rednet is already running", 2) end bRunning = true @@ -227,12 +346,12 @@ function run() if sEvent == "modem_message" then -- Got a modem message, process it and add it to the rednet event queue local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4 - if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then - if type( tMessage ) == "table" and tMessage.nMessageID then - if not tReceivedMessages[ tMessage.nMessageID ] then - tReceivedMessages[ tMessage.nMessageID ] = true - tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID - os.queueEvent( "rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol ) + if isOpen(sModem) and (nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST) then + if type(tMessage) == "table" and tMessage.nMessageID then + if not tReceivedMessages[tMessage.nMessageID] then + tReceivedMessages[tMessage.nMessageID] = true + tReceivedMessageTimeouts[os.startTimer(30)] = tMessage.nMessageID + os.queueEvent("rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol) end end end @@ -241,23 +360,23 @@ function run() -- Got a rednet message (queued from above), respond to dns lookup local nSenderID, tMessage, sProtocol = p1, p2, p3 if sProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup" then - local sHostname = tHostnames[ tMessage.sProtocol ] + local sHostname = tHostnames[tMessage.sProtocol] if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then - rednet.send( nSenderID, { + rednet.send(nSenderID, { sType = "lookup response", sHostname = sHostname, sProtocol = tMessage.sProtocol, - }, "dns" ) + }, "dns") end end elseif sEvent == "timer" then -- Got a timer event, use it to clear the event queue local nTimer = p1 - local nMessage = tReceivedMessageTimeouts[ nTimer ] + local nMessage = tReceivedMessageTimeouts[nTimer] if nMessage then - tReceivedMessageTimeouts[ nTimer ] = nil - tReceivedMessages[ nMessage ] = nil + tReceivedMessageTimeouts[nTimer] = nil + tReceivedMessages[nMessage] = nil end end end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/settings.lua b/src/main/resources/data/computercraft/lua/rom/apis/settings.lua index 54da34a32..c1fcb45f6 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/settings.lua @@ -1,62 +1,197 @@ -local expect = dofile("rom/modules/main/cc/expect.lua").expect +--- The settings API allows to store values and save them to a file for +-- persistent configurations for CraftOS and your programs. +-- +-- By default, the settings API will load its configuration from the +-- `/.settings` file. One can then use @{settings.save} to update the file. +-- +-- @module settings -local tSettings = {} +local expect = dofile("rom/modules/main/cc/expect.lua") +local type, expect, field = type, expect.expect, expect.field -function set( sName, value ) - expect(1, sName, "string") +local details, values = {}, {} + +local function reserialize(value) + if type(value) ~= "table" then return value end + return textutils.unserialize(textutils.serialize(value)) +end + +local function copy(value) + if type(value) ~= "table" then return value end + local result = {} + for k, v in pairs(value) do result[k] = copy(v) end + return result +end + +local valid_types = { "number", "string", "boolean", "table" } +for _, v in ipairs(valid_types) do valid_types[v] = true end + +--- Define a new setting, optional specifying various properties about it. +-- +-- While settings do not have to be added before being used, doing so allows +-- you to provide defaults and additional metadata. +-- +-- @tparam string name The name of this option +-- @tparam[opt] { description? = string, default? = value, type? = string } options +-- Options for this setting. This table accepts the following fields: +-- +-- - `description`: A description which may be printed when running the `set` program. +-- - `default`: A default value, which is returned by @{settings.get} if the +-- setting has not been changed. +-- - `type`: Require values to be of this type. @{set|Setting} the value to another type +-- will error. +function define(name, options) + expect(1, name, "string") + expect(2, options, "table", nil) + + if options then + options = { + description = field(options, "description", "string", "nil"), + default = reserialize(field(options, "default", "number", "string", "boolean", "table", "nil")), + type = field(options, "type", "string", "nil"), + } + + if options.type and not valid_types[options.type] then + error(("Unknown type %q. Expected one of %s."):format(options.type, table.concat(valid_types, ", ")), 2) + end + else + options = {} + end + + details[name] = options +end + +--- Remove a @{define|definition} of a setting. +-- +-- If a setting has been changed, this does not remove its value. Use @{settings.unset} +-- for that. +-- +-- @tparam string name The name of this option +function undefine(name) + expect(1, name, "string") + details[name] = nil +end + +local function set_value(name, value) + local new = reserialize(value) + local old = values[name] + if old == nil then + local opt = details[name] + old = opt and opt.default + end + + values[name] = new + if old ~= new then + -- This should be safe, as os.queueEvent copies values anyway. + os.queueEvent("setting_changed", name, new, old) + end +end + +--- Set the value of a setting. +-- +-- @tparam string name The name of the setting to set +-- @param value The setting's value. This cannot be `nil`, and must be +-- serialisable by @{textutils.serialize}. +-- @throws If this value cannot be serialised +-- @see settings.unset +function set(name, value) + expect(1, name, "string") expect(2, value, "number", "string", "boolean", "table") - if type(value) == "table" then - -- Ensure value is serializeable - value = textutils.unserialize( textutils.serialize(value) ) - end - tSettings[ sName ] = value + local opt = details[name] + if opt and opt.type then expect(2, value, opt.type) end + + set_value(name, value) end -local copy -function copy( value ) - if type(value) == "table" then - local result = {} - for k, v in pairs(value) do - result[k] = copy(v) - end - return result - else - return value - end -end - -function get( sName, default ) - expect(1, sName, "string") - local result = tSettings[ sName ] +--- Get the value of a setting. +-- +-- @tparam string name The name of the setting to get. +-- @param[opt] default The value to use should there be pre-existing value for +-- this setting. If not given, it will use the setting's default value if given, +-- or `nil` otherwise. +-- @return The setting's, or the default if the setting has not been changed. +function get(name, default) + expect(1, name, "string") + local result = values[name] if result ~= nil then return copy(result) - else + elseif default ~= nil then return default + else + local opt = details[name] + return opt and copy(opt.default) end end -function unset( sName ) - expect(1, sName, "string") - tSettings[ sName ] = nil +--- Get details about a specific setting. +-- +-- @tparam string name The name of the setting to get. +-- @treturn { description? = string, default? = value, type? = string, value? = value } +-- Information about this setting. This includes all information from @{settings.define}, +-- as well as this setting's value. +function getDetails(name) + expect(1, name, "string") + local deets = copy(details[name]) or {} + deets.value = values[name] + deets.changed = deets.value ~= nil + if deets.value == nil then deets.value = deets.default end + return deets end +--- Remove the value of a setting, setting it to the default. +-- +-- @{settings.get} will return the default value until the setting's value is +-- @{settings.set|set}, or the computer is rebooted. +-- +-- @tparam string name The name of the setting to unset. +-- @see settings.set +-- @see settings.clear +function unset(name) + expect(1, name, "string") + set_value(name, nil) +end + +--- Resets the value of all settings. Equivalent to calling @{settings.unset} +--- on every setting. +-- +-- @see settings.unset function clear() - tSettings = {} + for name in pairs(values) do + set_value(name, nil) + end end +--- Get the names of all currently defined settings. +-- +-- @treturn { string } An alphabetically sorted list of all currently-defined +-- settings. function getNames() - local result = {} - for k in pairs( tSettings ) do - result[ #result + 1 ] = k + local result, n = {}, 1 + for k in pairs(details) do + result[n], n = k, n + 1 + end + for k in pairs(values) do + if not details[k] then result[n], n = k, n + 1 end end table.sort(result) return result end -function load( sPath ) - expect(1, sPath, "string") - local file = fs.open( sPath, "r" ) +--- Load settings from the given file. +-- +-- Existing settings will be merged with any pre-existing ones. Conflicting +-- entries will be overwritten, but any others will be preserved. +-- +-- @tparam[opt] string sPath The file to load from, defaulting to `.settings`. +-- @treturn boolean Whether settings were successfully read from this +-- file. Reasons for failure may include the file not existing or being +-- corrupted. +-- +-- @see settings.save +function load(sPath) + expect(1, sPath, "string", "nil") + local file = fs.open(sPath or ".settings", "r") if not file then return false end @@ -64,29 +199,41 @@ function load( sPath ) local sText = file.readAll() file.close() - local tFile = textutils.unserialize( sText ) + local tFile = textutils.unserialize(sText) if type(tFile) ~= "table" then return false end for k, v in pairs(tFile) do - if type(k) == "string" and - (type(v) == "string" or type(v) == "number" or type(v) == "boolean" or type(v) == "table") then - set( k, v ) + local ty_v = type(k) + if type(k) == "string" and (ty_v == "string" or ty_v == "number" or ty_v == "boolean" or ty_v == "table") then + local opt = details[name] + if not opt or not opt.type or ty_v == opt.type then + set_value(k, v) + end end end return true end -function save( sPath ) - expect(1, sPath, "string") - local file = fs.open( sPath, "w" ) +--- Save settings to the given file. +-- +-- This will entirely overwrite the pre-existing file. Settings defined in the +-- file, but not currently loaded will be removed. +-- +-- @tparam[opt] string sPath The path to save settings to, defaulting to `.settings`. +-- @treturn boolean If the settings were successfully saved. +-- +-- @see settings.load +function save(sPath) + expect(1, sPath, "string", "nil") + local file = fs.open(sPath or ".settings", "w") if not file then return false end - file.write( textutils.serialize( tSettings ) ) + file.write(textutils.serialize(values)) file.close() return true diff --git a/src/main/resources/data/computercraft/lua/rom/apis/term.lua b/src/main/resources/data/computercraft/lua/rom/apis/term.lua index 706bd16f6..7461a137c 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/term.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/term.lua @@ -1,26 +1,49 @@ +--- The Terminal API provides functions for writing text to the terminal and +-- monitors, and drawing ASCII graphics. +-- +-- @module term + local expect = dofile("rom/modules/main/cc/expect.lua").expect local native = term.native and term.native() or term local redirectTarget = native -local function wrap( _sFunction ) - return function( ... ) - return redirectTarget[ _sFunction ]( ... ) +local function wrap(_sFunction) + return function(...) + return redirectTarget[_sFunction](...) end end -local term = {} +local term = _ENV -term.redirect = function( target ) +--- Redirects terminal output to a monitor, a @{window}, or any other custom +-- terminal object. Once the redirect is performed, any calls to a "term" +-- function - or to a function that makes use of a term function, as @{print} - +-- will instead operate with the new terminal object. +-- +-- A "terminal object" is simply a table that contains functions with the same +-- names - and general features - as those found in the term table. For example, +-- a wrapped monitor is suitable. +-- +-- The redirect can be undone by pointing back to the previous terminal object +-- (which this function returns whenever you switch). +-- +-- @tparam Redirect target The terminal redirect the @{term} API will draw to. +-- @treturn Redirect The previous redirect object, as returned by +-- @{term.current}. +-- @usage +-- Redirect to a monitor on the right of the computer. +-- term.redirect(peripheral.wrap("right")) +term.redirect = function(target) expect(1, target, "table") if target == term or target == _G.term then - error( "term is not a recommended redirect target, try term.current() instead", 2 ) + error("term is not a recommended redirect target, try term.current() instead", 2) end - for k, v in pairs( native ) do - if type( k ) == "string" and type( v ) == "function" then - if type( target[k] ) ~= "function" then + for k, v in pairs(native) do + if type(k) == "string" and type(v) == "function" then + if type(target[k]) ~= "function" then target[k] = function() - error( "Redirect object is missing method " .. k .. ".", 2 ) + error("Redirect object is missing method " .. k .. ".", 2) end end end @@ -30,31 +53,36 @@ term.redirect = function( target ) return oldRedirectTarget end +--- Returns the current terminal object of the computer. +-- +-- @treturn Redirect The current terminal redirect +-- @usage +-- Create a new @{window} which draws to the current redirect target +-- window.create(term.current(), 1, 1, 10, 10) term.current = function() return redirectTarget end +--- Get the native terminal object of the current computer. +-- +-- It is recommended you do not use this function unless you absolutely have +-- to. In a multitasked environment, @{term.native} will _not_ be the current +-- terminal object, and so drawing may interfere with other programs. +-- +-- @treturn Redirect The native terminal redirect. term.native = function() - -- NOTE: please don't use this function unless you have to. - -- If you're running in a redirected or multitasked enviorment, term.native() will NOT be - -- the current terminal when your program starts up. It is far better to use term.current() return native end -- Some methods shouldn't go through redirects, so we move them to the main -- term API. -for _, method in ipairs { "nativePaletteColor", "nativePaletteColour"} do +for _, method in ipairs { "nativePaletteColor", "nativePaletteColour" } do term[method] = native[method] native[method] = nil end -for k, v in pairs( native ) do - if type( k ) == "string" and type( v ) == "function" and term[k] == nil then - term[k] = wrap( k ) +for k, v in pairs(native) do + if type(k) == "string" and type(v) == "function" and rawget(term, k) == nil then + term[k] = wrap(k) end end - -local env = _ENV -for k, v in pairs( term ) do - env[k] = v -end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index 38360ea71..d087c570c 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -1,32 +1,65 @@ -local expect = dofile("rom/modules/main/cc/expect.lua").expect +--- The `textutils` API provides helpful utilities for formatting and +-- manipulating strings. +-- +-- @module textutils -function slowWrite( sText, nRate ) +local expect = dofile("rom/modules/main/cc/expect.lua") +local expect, field = expect.expect, expect.field + +--- Slowly writes string text at current cursor position, +-- character-by-character. +-- +-- Like @{write}, this does not insert a newline at the end. +-- +-- @tparam string sText The the text to write to the screen +-- @tparam[opt] number nRate The number of characters to write each second, +-- Defaults to 20. +-- @usage textutils.slowWrite("Hello, world!") +-- @usage textutils.slowWrite("Hello, world!", 5) +function slowWrite(sText, nRate) expect(2, nRate, "number", "nil") nRate = nRate or 20 if nRate < 0 then - error( "Rate must be positive", 2 ) + error("Rate must be positive", 2) end local nSleep = 1 / nRate - sText = tostring( sText ) + sText = tostring(sText) local x, y = term.getCursorPos() local len = #sText for n = 1, len do - term.setCursorPos( x, y ) - sleep( nSleep ) - local nLines = write( string.sub( sText, 1, n ) ) + term.setCursorPos(x, y) + sleep(nSleep) + local nLines = write(string.sub(sText, 1, n)) local _, newY = term.getCursorPos() y = newY - nLines end end -function slowPrint( sText, nRate ) - slowWrite( sText, nRate ) +--- Slowly prints string text at current cursor position, +-- character-by-character. +-- +-- Like @{print}, this inserts a newline after printing. +-- +-- @tparam string sText The the text to write to the screen +-- @tparam[opt] number nRate The number of characters to write each second, +-- Defaults to 20. +-- @usage textutils.slowPrint("Hello, world!") +-- @usage textutils.slowPrint("Hello, world!", 5) +function slowPrint(sText, nRate) + slowWrite(sText, nRate) print() end -function formatTime( nTime, bTwentyFourHour ) +--- Takes input time and formats it in a more readable format such as `6:30 PM`. +-- +-- @tparam number nTime The time to format, as provided by @{os.time}. +-- @tparam[opt] boolean bTwentyFourHour Whether to format this as a 24-hour +-- clock (`18:30`) rather than a 12-hour one (`6:30 AM`) +-- @treturn string The formatted time +-- @usage textutils.formatTime(os.time()) +function formatTime(nTime, bTwentyFourHour) expect(1, nTime, "number") expect(2, bTwentyFourHour, "boolean", "nil") local sTOD = nil @@ -44,26 +77,26 @@ function formatTime( nTime, bTwentyFourHour ) local nHour = math.floor(nTime) local nMinute = math.floor((nTime - nHour) * 60) if sTOD then - return string.format( "%d:%02d %s", nHour, nMinute, sTOD ) + return string.format("%d:%02d %s", nHour, nMinute, sTOD) else - return string.format( "%d:%02d", nHour, nMinute ) + return string.format("%d:%02d", nHour, nMinute) end end -local function makePagedScroll( _term, _nFreeLines ) +local function makePagedScroll(_term, _nFreeLines) local nativeScroll = _term.scroll local nFreeLines = _nFreeLines or 0 - return function( _n ) + return function(_n) for _ = 1, _n do - nativeScroll( 1 ) + nativeScroll(1) if nFreeLines <= 0 then local _, h = _term.getSize() - _term.setCursorPos( 1, h ) - _term.write( "Press any key to continue" ) - os.pullEvent( "key" ) + _term.setCursorPos(1, h) + _term.write("Press any key to continue") + os.pullEvent("key") _term.clearLine() - _term.setCursorPos( 1, h ) + _term.setCursorPos(1, h) else nFreeLines = nFreeLines - 1 end @@ -71,38 +104,55 @@ local function makePagedScroll( _term, _nFreeLines ) end end -function pagedPrint( _sText, _nFreeLines ) +--- Prints a given string to the display. +-- +-- If the action can be completed without scrolling, it acts much the same as +-- @{print}; otherwise, it will throw up a "Press any key to continue" prompt at +-- the bottom of the display. Each press will cause it to scroll down and write +-- a single line more before prompting again, if need be. +-- +-- @tparam string _sText The text to print to the screen. +-- @tparam[opt] number _nFreeLines The number of lines which will be +-- automatically scrolled before the first prompt appears (meaning _nFreeLines + +-- 1 lines will be printed). This can be set to the terminal's height - 2 to +-- always try to fill the screen. Defaults to 0, meaning only one line is +-- displayed before prompting. +-- @treturn number The number of lines printed. +-- @usage +-- local width, height = term.getSize() +-- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2) +function pagedPrint(_sText, _nFreeLines) expect(2, _nFreeLines, "number", "nil") -- Setup a redirector local oldTerm = term.current() local newTerm = {} - for k, v in pairs( oldTerm ) do + for k, v in pairs(oldTerm) do newTerm[k] = v end - newTerm.scroll = makePagedScroll( oldTerm, _nFreeLines ) - term.redirect( newTerm ) + newTerm.scroll = makePagedScroll(oldTerm, _nFreeLines) + term.redirect(newTerm) -- Print the text local result - local ok, err = pcall( function() + local ok, err = pcall(function() if _sText ~= nil then - result = print( _sText ) + result = print(_sText) else result = print() end - end ) + end) -- Removed the redirector - term.redirect( oldTerm ) + term.redirect(oldTerm) -- Propogate errors if not ok then - error( err, 0 ) + error(err, 0) end return result end -local function tabulateCommon( bPaged, ... ) +local function tabulateCommon(bPaged, ...) local tAll = table.pack(...) for i = 1, tAll.n do expect(i, tAll[i], "number", "table") @@ -110,17 +160,17 @@ local function tabulateCommon( bPaged, ... ) local w, h = term.getSize() local nMaxLen = w / 8 - for n, t in ipairs( tAll ) do + for n, t in ipairs(tAll) do if type(t) == "table" then for nu, sItem in pairs(t) do - if type( sItem ) ~= "string" then - error( "bad argument #" .. n .. "." .. nu .. " (expected string, got " .. type( sItem ) .. ")", 3 ) + if type(sItem) ~= "string" then + error("bad argument #" .. n .. "." .. nu .. " (expected string, got " .. type(sItem) .. ")", 3) end - nMaxLen = math.max( #sItem + 1, nMaxLen ) + nMaxLen = math.max(#sItem + 1, nMaxLen) end end end - local nCols = math.floor( w / nMaxLen ) + local nCols = math.floor(w / nMaxLen) local nLines = 0 local function newLine() if bPaged and nLines >= h - 3 then @@ -131,9 +181,9 @@ local function tabulateCommon( bPaged, ... ) nLines = nLines + 1 end - local function drawCols( _t ) + local function drawCols(_t) local nCol = 1 - for _, s in ipairs( _t ) do + for _, s in ipairs(_t) do if nCol > nCols then nCol = 1 newLine() @@ -141,61 +191,81 @@ local function tabulateCommon( bPaged, ... ) local cx, cy = term.getCursorPos() cx = 1 + (nCol - 1) * nMaxLen - term.setCursorPos( cx, cy ) - term.write( s ) + term.setCursorPos(cx, cy) + term.write(s) nCol = nCol + 1 end print() end - for _, t in ipairs( tAll ) do + for _, t in ipairs(tAll) do if type(t) == "table" then if #t > 0 then - drawCols( t ) + drawCols(t) end elseif type(t) == "number" then - term.setTextColor( t ) + term.setTextColor(t) end end end -function tabulate( ... ) - return tabulateCommon( false, ... ) +--- Prints tables in a structured form. +-- +-- This accepts multiple arguments, either a table or a number. When +-- encountering a table, this will be treated as a table row, with each column +-- width being auto-adjusted. +-- +-- When encountering a number, this sets the text color of the subsequent rows to it. +-- +-- @tparam {string...}|number ... The rows and text colors to display. +-- @usage textutils.tabulate(colors.orange, { "1", "2", "3" }, colors.lightBlue, { "A", "B", "C" }) +function tabulate(...) + return tabulateCommon(false, ...) end -function pagedTabulate( ... ) - return tabulateCommon( true, ... ) +--- Prints tables in a structured form, stopping and prompting for input should +-- the result not fit on the terminal. +-- +-- This functions identically to @{textutils.tabulate}, but will prompt for user +-- input should the whole output not fit on the display. +-- +-- @tparam {string...}|number ... The rows and text colors to display. +-- @usage textutils.tabulate(colors.orange, { "1", "2", "3" }, colors.lightBlue, { "A", "B", "C" }) +-- @see textutils.tabulate +-- @see textutils.pagedPrint +function pagedTabulate(...) + return tabulateCommon(true, ...) end local g_tLuaKeywords = { - [ "and" ] = true, - [ "break" ] = true, - [ "do" ] = true, - [ "else" ] = true, - [ "elseif" ] = true, - [ "end" ] = true, - [ "false" ] = true, - [ "for" ] = true, - [ "function" ] = true, - [ "if" ] = true, - [ "in" ] = true, - [ "local" ] = true, - [ "nil" ] = true, - [ "not" ] = true, - [ "or" ] = true, - [ "repeat" ] = true, - [ "return" ] = true, - [ "then" ] = true, - [ "true" ] = true, - [ "until" ] = true, - [ "while" ] = true, + ["and"] = true, + ["break"] = true, + ["do"] = true, + ["else"] = true, + ["elseif"] = true, + ["end"] = true, + ["false"] = true, + ["for"] = true, + ["function"] = true, + ["if"] = true, + ["in"] = true, + ["local"] = true, + ["nil"] = true, + ["not"] = true, + ["or"] = true, + ["repeat"] = true, + ["return"] = true, + ["then"] = true, + ["true"] = true, + ["until"] = true, + ["while"] = true, } -local function serializeImpl( t, tTracking, sIndent ) +local function serializeImpl(t, tTracking, sIndent) local sType = type(t) if sType == "table" then if tTracking[t] ~= nil then - error( "Cannot serialize table with recursive entries", 0 ) + error("Cannot serialize table with recursive entries", 0) end tTracking[t] = true @@ -209,15 +279,15 @@ local function serializeImpl( t, tTracking, sIndent ) local tSeen = {} for k, v in ipairs(t) do tSeen[k] = true - sResult = sResult .. sSubIndent .. serializeImpl( v, tTracking, sSubIndent ) .. ",\n" + sResult = sResult .. sSubIndent .. serializeImpl(v, tTracking, sSubIndent) .. ",\n" end for k, v in pairs(t) do if not tSeen[k] then local sEntry - if type(k) == "string" and not g_tLuaKeywords[k] and string.match( k, "^[%a_][%a%d_]*$" ) then - sEntry = k .. " = " .. serializeImpl( v, tTracking, sSubIndent ) .. ",\n" + if type(k) == "string" and not g_tLuaKeywords[k] and string.match(k, "^[%a_][%a%d_]*$") then + sEntry = k .. " = " .. serializeImpl(v, tTracking, sSubIndent) .. ",\n" else - sEntry = "[ " .. serializeImpl( k, tTracking, sSubIndent ) .. " ] = " .. serializeImpl( v, tTracking, sSubIndent ) .. ",\n" + sEntry = "[ " .. serializeImpl(k, tTracking, sSubIndent) .. " ] = " .. serializeImpl(v, tTracking, sSubIndent) .. ",\n" end sResult = sResult .. sSubIndent .. sEntry end @@ -227,31 +297,52 @@ local function serializeImpl( t, tTracking, sIndent ) end elseif sType == "string" then - return string.format( "%q", t ) + return string.format("%q", t) elseif sType == "number" or sType == "boolean" or sType == "nil" then return tostring(t) else - error( "Cannot serialize type " .. sType, 0 ) + error("Cannot serialize type " .. sType, 0) end end -empty_json_array = setmetatable({}, { - __newindex = function() - error("attempt to mutate textutils.empty_json_array", 2) - end, -}) +local function mk_tbl(str, name) + local msg = "attempt to mutate textutils." .. name + return setmetatable({}, { + __newindex = function() error(msg, 2) end, + __tostring = function() return str end, + }) +end -local function serializeJSONImpl( t, tTracking, bNBTStyle ) +--- A table representing an empty JSON array, in order to distinguish it from an +-- empty JSON object. +-- +-- The contents of this table should not be modified. +-- +-- @usage textutils.serialiseJSON(textutils.empty_json_array) +-- @see textutils.serialiseJSON +-- @see textutils.unserialiseJSON +empty_json_array = mk_tbl("[]", "empty_json_array") + +--- A table representing the JSON null value. +-- +-- The contents of this table should not be modified. +-- +-- @usage textutils.serialiseJSON(textutils.json_null) +-- @see textutils.serialiseJSON +-- @see textutils.unserialiseJSON +json_null = mk_tbl("null", "json_null") + +local function serializeJSONImpl(t, tTracking, bNBTStyle) local sType = type(t) - if t == empty_json_array then - return "[]" + if t == empty_json_array then return "[]" + elseif t == json_null then return "null" elseif sType == "table" then if tTracking[t] ~= nil then - error( "Cannot serialize table with recursive entries", 0 ) + error("Cannot serialize table with recursive entries", 0) end tTracking[t] = true @@ -268,9 +359,9 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) if type(k) == "string" then local sEntry if bNBTStyle then - sEntry = tostring(k) .. ":" .. serializeJSONImpl( v, tTracking, bNBTStyle ) + sEntry = tostring(k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle) else - sEntry = string.format( "%q", k ) .. ":" .. serializeJSONImpl( v, tTracking, bNBTStyle ) + sEntry = string.format("%q", k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle) end if nObjectSize == 0 then sObjectResult = sObjectResult .. sEntry @@ -281,7 +372,7 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) end end for _, v in ipairs(t) do - local sEntry = serializeJSONImpl( v, tTracking, bNBTStyle ) + local sEntry = serializeJSONImpl(v, tTracking, bNBTStyle) if nArraySize == 0 then sArrayResult = sArrayResult .. sEntry else @@ -299,27 +390,247 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) end elseif sType == "string" then - return string.format( "%q", t ) + return string.format("%q", t) elseif sType == "number" or sType == "boolean" then return tostring(t) else - error( "Cannot serialize type " .. sType, 0 ) + error("Cannot serialize type " .. sType, 0) end end -function serialize( t ) - local tTracking = {} - return serializeImpl( t, tTracking, "" ) +local unserialise_json +do + local sub, find, match, concat, tonumber = string.sub, string.find, string.match, table.concat, tonumber + + --- Skip any whitespace + local function skip(str, pos) + local _, last = find(str, "^[ \n\r\v]+", pos) + if last then return last + 1 else return pos end + end + + local escapes = { + ["b"] = '\b', ["f"] = '\f', ["n"] = '\n', ["r"] = '\r', ["t"] = '\t', + ["\""] = "\"", ["/"] = "/", ["\\"] = "\\", + } + + local mt = {} + + local function error_at(pos, msg, ...) + if select('#', ...) > 0 then msg = msg:format(...) end + error(setmetatable({ pos = pos, msg = msg }, mt)) + end + + local function expected(pos, actual, exp) + if actual == "" then actual = "end of input" else actual = ("%q"):format(actual) end + error_at(pos, "Unexpected %s, expected %s.", actual, exp) + end + + local function parse_string(str, pos) + local buf, n = {}, 1 + + while true do + local c = sub(str, pos, pos) + if c == "" then error_at(pos, "Unexpected end of input, expected '\"'.") end + if c == '"' then break end + + if c == '\\' then + -- Handle the various escapes + c = sub(str, pos + 1, pos + 1) + if c == "" then error_at(pos, "Unexpected end of input, expected escape sequence.") end + + if c == "u" then + local num_str = match(str, "^%x%x%x%x", pos + 2) + if not num_str then error_at(pos, "Malformed unicode escape %q.", sub(str, pos + 2, pos + 5)) end + buf[n], n, pos = utf8.char(tonumber(num_str, 16)), n + 1, pos + 6 + else + local unesc = escapes[c] + if not unesc then error_at(pos + 1, "Unknown escape character %q.", unesc) end + buf[n], n, pos = unesc, n + 1, pos + 2 + end + elseif c >= '\x20' then + buf[n], n, pos = c, n + 1, pos + 1 + else + error_at(pos + 1, "Unescaped whitespace %q.", c) + end + end + + return concat(buf, "", 1, n - 1), pos + 1 + end + + local valid = { b = true, B = true, s = true, S = true, l = true, L = true, f = true, F = true, d = true, D = true } + local function parse_number(str, pos, opts) + local _, last, num_str = find(str, '^(-?%d+%.?%d*[eE]?[+-]?%d*)', pos) + local val = tonumber(num_str) + if not val then error_at(pos, "Malformed number %q.", num_str) end + + if opts.nbt_style and valid[sub(str, pos + 1, pos + 1)] then return val, last + 2 end + + return val, last + 1 + end + + local function parse_ident(str, pos) + local _, last, val = find(str, '^([%a][%w_]*)', pos) + return val, last + 1 + end + + local function decode_impl(str, pos, opts) + local c = sub(str, pos, pos) + if c == '"' then return parse_string(str, pos + 1) + elseif c == "-" or c >= "0" and c <= "9" then return parse_number(str, pos, opts) + elseif c == "t" then + if sub(str, pos + 1, pos + 3) == "rue" then return true, pos + 4 end + elseif c == 'f' then + if sub(str, pos + 1, pos + 4) == "alse" then return false, pos + 5 end + elseif c == 'n' then + if sub(str, pos + 1, pos + 3) == "ull" then + if opts.parse_null then + return json_null, pos + 4 + else + return nil, pos + 4 + end + end + elseif c == "{" then + local obj = {} + + pos = skip(str, pos + 1) + c = sub(str, pos, pos) + + if c == "" then return error_at(pos, "Unexpected end of input, expected '}'.") end + if c == "}" then return obj, pos + 1 end + + while true do + local key, value + if c == "\"" then key, pos = parse_string(str, pos + 1) + elseif opts.nbt_style then key, pos = parse_ident(str, pos) + else return expected(pos, c, "object key") + end + + pos = skip(str, pos) + + c = sub(str, pos, pos) + if c ~= ":" then return expected(pos, c, "':'") end + + value, pos = decode_impl(str, skip(str, pos + 1), opts) + obj[key] = value + + -- Consume the next delimiter + pos = skip(str, pos) + c = sub(str, pos, pos) + if c == "}" then break + elseif c == "," then pos = skip(str, pos + 1) + else return expected(pos, c, "',' or '}'") + end + + c = sub(str, pos, pos) + end + + return obj, pos + 1 + + elseif c == "[" then + local arr, n = {}, 1 + + pos = skip(str, pos + 1) + c = sub(str, pos, pos) + + if c == "" then return expected(pos, c, "']'") end + if c == "]" then return empty_json_array, pos + 1 end + + while true do + n, arr[n], pos = n + 1, decode_impl(str, pos, opts) + + -- Consume the next delimiter + pos = skip(str, pos) + c = sub(str, pos, pos) + if c == "]" then break + elseif c == "," then pos = skip(str, pos + 1) + else return expected(pos, c, "',' or ']'") + end + end + + return arr, pos + 1 + elseif c == "" then error_at(pos, 'Unexpected end of input.') + end + + error_at(pos, "Unexpected character %q.", c) + end + + --- Converts a serialised JSON string back into a reassembled Lua object. + -- + -- This may be used with @{textutils.serializeJSON}, or when communicating + -- with command blocks or web APIs. + -- + -- @tparam string s The serialised string to deserialise. + -- @tparam[opt] { nbt_style? = boolean, parse_null? = boolean } options + -- Options which control how this JSON object is parsed. + -- + -- - `nbt_style`: When true, this will accept [stringified NBT][nbt] strings, + -- as produced by many commands. + -- - `parse_null`: When true, `null` will be parsed as @{json_null}, rather + -- than `nil`. + -- + -- [nbt]: https://minecraft.gamepedia.com/NBT_format + -- @return[1] The deserialised object + -- @treturn[2] nil If the object could not be deserialised. + -- @treturn string A message describing why the JSON string is invalid. + unserialise_json = function(s, options) + expect(1, s, "string") + expect(2, options, "table", "nil") + + if options then + field(options, "nbt_style", "boolean", "nil") + field(options, "nbt_style", "boolean", "nil") + else + options = {} + end + + local ok, res, pos = pcall(decode_impl, s, skip(s, 1), options) + if not ok then + if type(res) == "table" and getmetatable(res) == mt then + return nil, ("Malformed JSON at position %d: %s"):format(res.pos, res.msg) + end + + error(res, 0) + end + + pos = skip(s, pos) + if pos <= #s then + return nil, ("Malformed JSON at position %d: Unexpected trailing character %q."):format(pos, sub(s, pos, pos)) + end + return res + + end end -function unserialize( s ) +--- Convert a Lua object into a textual representation, suitable for +-- saving in a file or pretty-printing. +-- +-- @param t The object to serialise +-- @treturn string The serialised representation +-- @throws If the object contains a value which cannot be +-- serialised. This includes functions and tables which appear multiple +-- times. +function serialize(t) + local tTracking = {} + return serializeImpl(t, tTracking, "") +end + +serialise = serialize -- GB version + +--- Converts a serialised string back into a reassembled Lua object. +-- +-- This is mainly used together with @{textutils.serialize}. +-- +-- @tparam string s The serialised string to deserialise. +-- @return[1] The deserialised object +-- @treturn[2] nil If the object could not be deserialised. +function unserialize(s) expect(1, s, "string") - local func = load( "return " .. s, "unserialize", "t", {} ) + local func = load("return " .. s, "unserialize", "t", {}) if func then - local ok, result = pcall( func ) + local ok, result = pcall(func) if ok then return result end @@ -327,14 +638,44 @@ function unserialize( s ) return nil end -function serializeJSON( t, bNBTStyle ) +unserialise = unserialize -- GB version + +--- Returns a JSON representation of the given data. +-- +-- This function attempts to guess whether a table is a JSON array or +-- object. However, empty tables are assumed to be empty objects - use +-- @{textutils.empty_json_array} to mark an empty array. +-- +-- This is largely intended for interacting with various functions from the +-- @{commands} API, though may also be used in making @{http} requests. +-- +-- @param t The value to serialise. Like @{textutils.serialise}, this should not +-- contain recursive tables or functions. +-- @tparam[opt] boolean bNBTStyle Whether to produce NBT-style JSON (non-quoted keys) +-- instead of standard JSON. +-- @treturn string The JSON representation of the input. +-- @throws If the object contains a value which cannot be +-- serialised. This includes functions and tables which appear multiple +-- times. +-- @usage textutils.serializeJSON({ values = { 1, "2", true } }) +function serializeJSON(t, bNBTStyle) expect(1, t, "table", "string", "number", "boolean") expect(2, bNBTStyle, "boolean", "nil") local tTracking = {} - return serializeJSONImpl( t, tTracking, bNBTStyle or false ) + return serializeJSONImpl(t, tTracking, bNBTStyle or false) end -function urlEncode( str ) +serialiseJSON = serializeJSON -- GB version + +unserializeJSON = unserialise_json +unserialiseJSON = unserialise_json + +--- Replaces certain characters in a string to make it safe for use in URLs or POST data. +-- +-- @tparam string str The string to encode +-- @treturn string The encoded string. +-- @usage print("https://example.com/?view=" .. textutils.urlEncode(read())) +function urlEncode(str) expect(1, str, "string") if str then str = string.gsub(str, "\n", "\r\n") @@ -346,40 +687,57 @@ function urlEncode( str ) else -- Non-ASCII (encode as UTF-8) return - string.format("%%%02X", 192 + bit32.band( bit32.arshift(n, 6), 31 ) ) .. - string.format("%%%02X", 128 + bit32.band( n, 63 ) ) + string.format("%%%02X", 192 + bit32.band(bit32.arshift(n, 6), 31)) .. + string.format("%%%02X", 128 + bit32.band(n, 63)) end - end ) + end) str = string.gsub(str, " ", "+") end return str end local tEmpty = {} -function complete( sSearchText, tSearchTable ) + +--- Provides a list of possible completions for a partial Lua expression. +-- +-- If the completed element is a table, suggestions will have `.` appended to +-- them. Similarly, functions have `(` appended to them. +-- +-- @tparam string sSearchText The partial expression to complete, such as a +-- variable name or table index. +-- +-- @tparam[opt] table tSearchTable The table to find variables in, defaulting to +-- the global environment (@{_G}). The function also searches the "parent" +-- environment via the `__index` metatable field. +-- +-- @treturn { string... } The (possibly empty) list of completions. +-- @see shell.setCompletionFunction +-- @see read +-- @usage textutils.complete( "pa", getfenv() ) +function complete(sSearchText, tSearchTable) expect(1, sSearchText, "string") expect(2, tSearchTable, "table", "nil") if g_tLuaKeywords[sSearchText] then return tEmpty end local nStart = 1 - local nDot = string.find( sSearchText, ".", nStart, true ) + local nDot = string.find(sSearchText, ".", nStart, true) local tTable = tSearchTable or _ENV while nDot do - local sPart = string.sub( sSearchText, nStart, nDot - 1 ) - local value = tTable[ sPart ] - if type( value ) == "table" then + local sPart = string.sub(sSearchText, nStart, nDot - 1) + local value = tTable[sPart] + if type(value) == "table" then tTable = value nStart = nDot + 1 - nDot = string.find( sSearchText, ".", nStart, true ) + nDot = string.find(sSearchText, ".", nStart, true) else return tEmpty end end - local nColon = string.find( sSearchText, ":", nStart, true ) + local nColon = string.find(sSearchText, ":", nStart, true) if nColon then - local sPart = string.sub( sSearchText, nStart, nColon - 1 ) - local value = tTable[ sPart ] - if type( value ) == "table" then + local sPart = string.sub(sSearchText, nStart, nColon - 1) + local value = tTable[sPart] + if type(value) == "table" then tTable = value nStart = nColon + 1 else @@ -387,24 +745,24 @@ function complete( sSearchText, tSearchTable ) end end - local sPart = string.sub( sSearchText, nStart ) + local sPart = string.sub(sSearchText, nStart) local nPartLength = #sPart local tResults = {} local tSeen = {} while tTable do - for k, v in pairs( tTable ) do + for k, v in pairs(tTable) do if not tSeen[k] and type(k) == "string" then - if string.find( k, sPart, 1, true ) == 1 then - if not g_tLuaKeywords[k] and string.match( k, "^[%a_][%a%d_]*$" ) then - local sResult = string.sub( k, nPartLength + 1 ) + if string.find(k, sPart, 1, true) == 1 then + if not g_tLuaKeywords[k] and string.match(k, "^[%a_][%a%d_]*$") then + local sResult = string.sub(k, nPartLength + 1) if nColon then if type(v) == "function" then - table.insert( tResults, sResult .. "(" ) + table.insert(tResults, sResult .. "(") elseif type(v) == "table" then - local tMetatable = getmetatable( v ) - if tMetatable and ( type( tMetatable.__call ) == "function" or type( tMetatable.__call ) == "table" ) then - table.insert( tResults, sResult .. "(" ) + local tMetatable = getmetatable(v) + if tMetatable and (type(tMetatable.__call) == "function" or type(tMetatable.__call) == "table") then + table.insert(tResults, sResult .. "(") end end else @@ -413,26 +771,21 @@ function complete( sSearchText, tSearchTable ) elseif type(v) == "table" and next(v) ~= nil then sResult = sResult .. "." end - table.insert( tResults, sResult ) + table.insert(tResults, sResult) end end end end tSeen[k] = true end - local tMetatable = getmetatable( tTable ) - if tMetatable and type( tMetatable.__index ) == "table" then + local tMetatable = getmetatable(tTable) + if tMetatable and type(tMetatable.__index) == "table" then tTable = tMetatable.__index else tTable = nil end end - table.sort( tResults ) + table.sort(tResults) return tResults end - --- GB versions -serialise = serialize -unserialise = unserialize -serialiseJSON = serializeJSON diff --git a/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua b/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua index c471212a4..32852f718 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua @@ -1,17 +1,20 @@ +--- The turtle API allows you to control your turtle. +-- +-- @module turtle if not turtle then - error( "Cannot load turtle API on computer", 2 ) + error("Cannot load turtle API on computer", 2) end -native = turtle.native or turtle +native = turtle.native or turtle --- @local -local function addCraftMethod( object ) - if peripheral.getType( "left" ) == "workbench" then - object.craft = function( ... ) - return peripheral.call( "left", "craft", ... ) +local function addCraftMethod(object) + if peripheral.getType("left") == "workbench" then + object.craft = function(...) + return peripheral.call("left", "craft", ...) end - elseif peripheral.getType( "right" ) == "workbench" then - object.craft = function( ... ) - return peripheral.call( "right", "craft", ... ) + elseif peripheral.getType("right") == "workbench" then + object.craft = function(...) + return peripheral.call("right", "craft", ...) end else object.craft = nil @@ -20,15 +23,15 @@ end -- Put commands into environment table local env = _ENV -for k, v in pairs( native ) do +for k, v in pairs(native) do if k == "equipLeft" or k == "equipRight" then - env[k] = function( ... ) - local result, err = v( ... ) - addCraftMethod( turtle ) + env[k] = function(...) + local result, err = v(...) + addCraftMethod(turtle) return result, err end else env[k] = v end end -addCraftMethod( env ) +addCraftMethod(env) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/vector.lua b/src/main/resources/data/computercraft/lua/rom/apis/vector.lua index 4d6c159f9..05dab327e 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/vector.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/vector.lua @@ -1,85 +1,178 @@ +--- The vector API provides methods to create and manipulate vectors. +-- +-- An introduction to vectors can be found on [Wikipedia][wiki]. +-- +-- [wiki]: http://en.wikipedia.org/wiki/Euclidean_vector +-- +-- @module vector +--- A 3-dimensional vector, with `x`, `y`, and `z` values. +-- +-- This is suitable for representing both position and directional vectors. +-- +-- @type Vector local vector = { - add = function( self, o ) - return vector.new( - self.x + o.x, - self.y + o.y, - self.z + o.z - ) - end, - sub = function( self, o ) - return vector.new( - self.x - o.x, - self.y - o.y, - self.z - o.z - ) - end, - mul = function( self, m ) - return vector.new( - self.x * m, - self.y * m, - self.z * m - ) - end, - div = function( self, m ) - return vector.new( - self.x / m, - self.y / m, - self.z / m - ) - end, - unm = function( self ) - return vector.new( - -self.x, - -self.y, - -self.z - ) - end, - dot = function( self, o ) - return self.x * o.x + self.y * o.y + self.z * o.z - end, - cross = function( self, o ) - return vector.new( - self.y * o.z - self.z * o.y, - self.z * o.x - self.x * o.z, - self.x * o.y - self.y * o.x - ) - end, - length = function( self ) - return math.sqrt( self.x * self.x + self.y * self.y + self.z * self.z ) - end, - normalize = function( self ) - return self:mul( 1 / self:length() ) - end, - round = function( self, nTolerance ) - nTolerance = nTolerance or 1.0 - return vector.new( - math.floor( (self.x + nTolerance * 0.5) / nTolerance ) * nTolerance, - math.floor( (self.y + nTolerance * 0.5) / nTolerance ) * nTolerance, - math.floor( (self.z + nTolerance * 0.5) / nTolerance ) * nTolerance - ) - end, - tostring = function( self ) - return self.x .. "," .. self.y .. "," .. self.z - end, + --- Adds two vectors together. + -- + -- @tparam Vector self The first vector to add. + -- @tparam Vector o The second vector to add. + -- @treturn Vector The resulting vector + -- @usage v1:add(v2) + -- @usage v1 + v2 + add = function(self, o) + return vector.new( + self.x + o.x, + self.y + o.y, + self.z + o.z + ) + end, + + --- Subtracts one vector from another. + -- + -- @tparam Vector self The vector to subtract from. + -- @tparam Vector o The vector to subtract. + -- @treturn Vector The resulting vector + -- @usage v1:sub(v2) + -- @usage v1 - v2 + sub = function(self, o) + return vector.new( + self.x - o.x, + self.y - o.y, + self.z - o.z + ) + end, + + --- Multiplies a vector by a scalar value. + -- + -- @tparam Vector self The vector to multiply. + -- @tparam number m The scalar value to multiply with. + -- @treturn Vector A vector with value `(x * m, y * m, z * m)`. + -- @usage v:mul(3) + -- @usage v * 3 + mul = function(self, m) + return vector.new( + self.x * m, + self.y * m, + self.z * m + ) + end, + + --- Divides a vector by a scalar value. + -- + -- @tparam Vector self The vector to divide. + -- @tparam number m The scalar value to divide by. + -- @treturn Vector A vector with value `(x / m, y / m, z / m)`. + -- @usage v:div(3) + -- @usage v / 3 + div = function(self, m) + return vector.new( + self.x / m, + self.y / m, + self.z / m + ) + end, + + --- Negate a vector + -- + -- @tparam Vector self The vector to negate. + -- @treturn Vector The negated vector. + -- @usage -v + unm = function(self) + return vector.new( + -self.x, + -self.y, + -self.z + ) + end, + + --- Compute the dot product of two vectors + -- + -- @tparam Vector self The first vector to compute the dot product of. + -- @tparam Vector o The second vector to compute the dot product of. + -- @treturn Vector The dot product of `self` and `o`. + -- @usage v1:dot(v2) + dot = function(self, o) + return self.x * o.x + self.y * o.y + self.z * o.z + end, + + --- Compute the cross product of two vectors + -- + -- @tparam Vector self The first vector to compute the cross product of. + -- @tparam Vector o The second vector to compute the cross product of. + -- @treturn Vector The cross product of `self` and `o`. + -- @usage v1:cross(v2) + cross = function(self, o) + return vector.new( + self.y * o.z - self.z * o.y, + self.z * o.x - self.x * o.z, + self.x * o.y - self.y * o.x + ) + end, + + --- Get the length (also referred to as magnitude) of this vector. + -- @tparam Vector self This vector. + -- @treturn number The length of this vector. + length = function(self) + return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) + end, + + --- Divide this vector by its length, producing with the same direction, but + -- of length 1. + -- + -- @tparam Vector self The vector to normalise + -- @treturn Vector The normalised vector + -- @usage v:normalize() + normalize = function(self) + return self:mul(1 / self:length()) + end, + + --- Construct a vector with each dimension rounded to the nearest value. + -- + -- @tparam Vector self The vector to round + -- @tparam[opt] number tolerance The tolerance that we should round to, + -- defaulting to 1. For instance, a tolerance of 0.5 will round to the + -- nearest 0.5. + -- @treturn Vector The rounded vector. + round = function(self, tolerance) + tolerance = tolerance or 1.0 + return vector.new( + math.floor((self.x + tolerance * 0.5) / tolerance) * tolerance, + math.floor((self.y + tolerance * 0.5) / tolerance) * tolerance, + math.floor((self.z + tolerance * 0.5) / tolerance) * tolerance + ) + end, + + --- Convert this vector into a string, for pretty printing. + -- + -- @tparam Vector self This vector. + -- @treturn string This vector's string representation. + -- @usage v:tostring() + -- @usage tostring(v) + tostring = function(self) + return self.x .. "," .. self.y .. "," .. self.z + end, } local vmetatable = { - __index = vector, - __add = vector.add, - __sub = vector.sub, - __mul = vector.mul, - __div = vector.div, - __unm = vector.unm, - __tostring = vector.tostring, + __index = vector, + __add = vector.add, + __sub = vector.sub, + __mul = vector.mul, + __div = vector.div, + __unm = vector.unm, + __tostring = vector.tostring, } -function new( x, y, z ) - local v = { - x = tonumber(x) or 0, - y = tonumber(y) or 0, - z = tonumber(z) or 0, - } - setmetatable( v, vmetatable ) - return v +--- Construct a new @{Vector} with the given coordinates. +-- +-- @tparam number x The X coordinate or direction of the vector. +-- @tparam number y The Y coordinate or direction of the vector. +-- @tparam number z The Z coordinate or direction of the vector. +-- @treturn Vector The constructed vector. +function new(x, y, z) + return setmetatable({ + x = tonumber(x) or 0, + y = tonumber(y) or 0, + z = tonumber(z) or 0, + }, vmetatable) end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/window.lua b/src/main/resources/data/computercraft/lua/rom/apis/window.lua index 0e24b7696..d93533f03 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/window.lua @@ -1,29 +1,76 @@ +--- The Window API allows easy definition of spaces within the display that can +-- be written/drawn to, then later redrawn/repositioned/etc as need be. The API +-- itself contains only one function, @{window.create}, which returns the +-- windows themselves. +-- +-- Windows are considered terminal objects - as such, they have access to nearly +-- all the commands in the term API (plus a few extras of their own, listed +-- within said API) and are valid targets to redirect to. +-- +-- Each window has a "parent" terminal object, which can be the computer's own +-- display, a monitor, another window or even other, user-defined terminal +-- objects. Whenever a window is rendered to, the actual screen-writing is +-- performed via that parent (or, if that has one too, then that parent, and so +-- forth). Bear in mind that the cursor of a window's parent will hence be moved +-- around etc when writing a given child window. +-- +-- Windows retain a memory of everything rendered "through" them (hence acting +-- as display buffers), and if the parent's display is wiped, the window's +-- content can be easily redrawn later. A window may also be flagged as +-- invisible, preventing any changes to it from being rendered until it's +-- flagged as visible once more. +-- +-- A parent terminal object may have multiple children assigned to it, and +-- windows may overlap. For example, the Multishell system functions by +-- assigning each tab a window covering the screen, each using the starting +-- terminal display as its parent, and only one of which is visible at a time. +-- +-- @module window + local expect = dofile("rom/modules/main/cc/expect.lua").expect local tHex = { - [ colors.white ] = "0", - [ colors.orange ] = "1", - [ colors.magenta ] = "2", - [ colors.lightBlue ] = "3", - [ colors.yellow ] = "4", - [ colors.lime ] = "5", - [ colors.pink ] = "6", - [ colors.gray ] = "7", - [ colors.lightGray ] = "8", - [ colors.cyan ] = "9", - [ colors.purple ] = "a", - [ colors.blue ] = "b", - [ colors.brown ] = "c", - [ colors.green ] = "d", - [ colors.red ] = "e", - [ colors.black ] = "f", + [colors.white] = "0", + [colors.orange] = "1", + [colors.magenta] = "2", + [colors.lightBlue] = "3", + [colors.yellow] = "4", + [colors.lime] = "5", + [colors.pink] = "6", + [colors.gray] = "7", + [colors.lightGray] = "8", + [colors.cyan] = "9", + [colors.purple] = "a", + [colors.blue] = "b", + [colors.brown] = "c", + [colors.green] = "d", + [colors.red] = "e", + [colors.black] = "f", } local type = type local string_rep = string.rep local string_sub = string.sub -function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) +--- Returns a terminal object that is a space within the specified parent +-- terminal object. This can then be used (or even redirected to) in the same +-- manner as eg a wrapped monitor. Refer to @{term|the term API} for a list of +-- functions available to it. +-- +-- @{term} itself may not be passed as the parent, though @{term.native} is +-- acceptable. Generally, @{term.current} or a wrapped monitor will be most +-- suitable, though windows may even have other windows assigned as their +-- parents. +-- +-- @tparam term.Redirect parent The parent terminal redirect to draw to. +-- @tparam number nX The x coordinate this window is drawn at in the parent terminal +-- @tparam number nY The y coordinate this window is drawn at in the parent terminal +-- @tparam number nWidth The width of this window +-- @tparam number nHeight The height of this window +-- @tparam[opt] boolean bStartVisible Whether this window is visible by +-- default. Defaults to `true`. +-- @treturn Window The constructed window +function create(parent, nX, nY, nWidth, nHeight, bStartVisible) expect(1, parent, "table") expect(2, nX, "number") expect(3, nY, "number") @@ -32,21 +79,21 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) expect(6, bStartVisible, "boolean", "nil") if parent == term then - error( "term is not a recommended window parent, try term.current() instead", 2 ) + error("term is not a recommended window parent, try term.current() instead", 2) end local sEmptySpaceLine local tEmptyColorLines = {} - local function createEmptyLines( nWidth ) - sEmptySpaceLine = string_rep( " ", nWidth ) + local function createEmptyLines(nWidth) + sEmptySpaceLine = string_rep(" ", nWidth) for n = 0, 15 do local nColor = 2 ^ n local sHex = tHex[nColor] - tEmptyColorLines[nColor] = string_rep( sHex, nWidth ) + tEmptyColorLines[nColor] = string_rep(sHex, nWidth) end end - createEmptyLines( nWidth ) + createEmptyLines(nWidth) -- Setup local bVisible = bStartVisible ~= false @@ -59,8 +106,8 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local tPalette = {} do local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] for y = 1, nHeight do tLines[y] = { text = sEmptyText, @@ -71,7 +118,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) for i = 0, 15 do local c = 2 ^ i - tPalette[c] = { parent.getPaletteColour( c ) } + tPalette[c] = { parent.getPaletteColour(c) } end end @@ -79,45 +126,45 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local function updateCursorPos() if nCursorX >= 1 and nCursorY >= 1 and nCursorX <= nWidth and nCursorY <= nHeight then - parent.setCursorPos( nX + nCursorX - 1, nY + nCursorY - 1 ) + parent.setCursorPos(nX + nCursorX - 1, nY + nCursorY - 1) else - parent.setCursorPos( 0, 0 ) + parent.setCursorPos(0, 0) end end local function updateCursorBlink() - parent.setCursorBlink( bCursorBlink ) + parent.setCursorBlink(bCursorBlink) end local function updateCursorColor() - parent.setTextColor( nTextColor ) + parent.setTextColor(nTextColor) end - local function redrawLine( n ) - local tLine = tLines[ n ] - parent.setCursorPos( nX, nY + n - 1 ) - parent.blit( tLine.text, tLine.textColor, tLine.backgroundColor ) + local function redrawLine(n) + local tLine = tLines[n] + parent.setCursorPos(nX, nY + n - 1) + parent.blit(tLine.text, tLine.textColor, tLine.backgroundColor) end local function redraw() for n = 1, nHeight do - redrawLine( n ) + redrawLine(n) end end local function updatePalette() - for k, v in pairs( tPalette ) do - parent.setPaletteColour( k, v[1], v[2], v[3] ) + for k, v in pairs(tPalette) do + parent.setPaletteColour(k, v[1], v[2], v[3]) end end - local function internalBlit( sText, sTextColor, sBackgroundColor ) + local function internalBlit(sText, sTextColor, sBackgroundColor) local nStart = nCursorX local nEnd = nStart + #sText - 1 if nCursorY >= 1 and nCursorY <= nHeight then if nStart <= nWidth and nEnd >= 1 then -- Modify line - local tLine = tLines[ nCursorY ] + local tLine = tLines[nCursorY] if nStart == 1 and nEnd == nWidth then tLine.text = sText tLine.textColor = sTextColor @@ -127,14 +174,14 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) if nStart < 1 then local nClipStart = 1 - nStart + 1 local nClipEnd = nWidth - nStart + 1 - sClippedText = string_sub( sText, nClipStart, nClipEnd ) - sClippedTextColor = string_sub( sTextColor, nClipStart, nClipEnd ) - sClippedBackgroundColor = string_sub( sBackgroundColor, nClipStart, nClipEnd ) + sClippedText = string_sub(sText, nClipStart, nClipEnd) + sClippedTextColor = string_sub(sTextColor, nClipStart, nClipEnd) + sClippedBackgroundColor = string_sub(sBackgroundColor, nClipStart, nClipEnd) elseif nEnd > nWidth then local nClipEnd = nWidth - nStart + 1 - sClippedText = string_sub( sText, 1, nClipEnd ) - sClippedTextColor = string_sub( sTextColor, 1, nClipEnd ) - sClippedBackgroundColor = string_sub( sBackgroundColor, 1, nClipEnd ) + sClippedText = string_sub(sText, 1, nClipEnd) + sClippedTextColor = string_sub(sTextColor, 1, nClipEnd) + sClippedBackgroundColor = string_sub(sBackgroundColor, 1, nClipEnd) else sClippedText = sText sClippedTextColor = sTextColor @@ -147,9 +194,9 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local sNewText, sNewTextColor, sNewBackgroundColor if nStart > 1 then local nOldEnd = nStart - 1 - sNewText = string_sub( sOldText, 1, nOldEnd ) .. sClippedText - sNewTextColor = string_sub( sOldTextColor, 1, nOldEnd ) .. sClippedTextColor - sNewBackgroundColor = string_sub( sOldBackgroundColor, 1, nOldEnd ) .. sClippedBackgroundColor + sNewText = string_sub(sOldText, 1, nOldEnd) .. sClippedText + sNewTextColor = string_sub(sOldTextColor, 1, nOldEnd) .. sClippedTextColor + sNewBackgroundColor = string_sub(sOldBackgroundColor, 1, nOldEnd) .. sClippedBackgroundColor else sNewText = sClippedText sNewTextColor = sClippedTextColor @@ -157,9 +204,9 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end if nEnd < nWidth then local nOldStart = nEnd + 1 - sNewText = sNewText .. string_sub( sOldText, nOldStart, nWidth ) - sNewTextColor = sNewTextColor .. string_sub( sOldTextColor, nOldStart, nWidth ) - sNewBackgroundColor = sNewBackgroundColor .. string_sub( sOldBackgroundColor, nOldStart, nWidth ) + sNewText = sNewText .. string_sub(sOldText, nOldStart, nWidth) + sNewTextColor = sNewTextColor .. string_sub(sOldTextColor, nOldStart, nWidth) + sNewBackgroundColor = sNewBackgroundColor .. string_sub(sOldBackgroundColor, nOldStart, nWidth) end tLine.text = sNewText @@ -169,7 +216,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) -- Redraw line if bVisible then - redrawLine( nCursorY ) + redrawLine(nCursorY) end end end @@ -182,28 +229,32 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end end - -- Terminal implementation + --- The window object. Refer to the @{window|module's documentation} for + -- a full description. + -- + -- @type Window + -- @see term.Redirect local window = {} - function window.write( sText ) - sText = tostring( sText ) - internalBlit( sText, string_rep( tHex[ nTextColor ], #sText ), string_rep( tHex[ nBackgroundColor ], #sText ) ) + function window.write(sText) + sText = tostring(sText) + internalBlit(sText, string_rep(tHex[nTextColor], #sText), string_rep(tHex[nBackgroundColor], #sText)) end - function window.blit( sText, sTextColor, sBackgroundColor ) + function window.blit(sText, sTextColor, sBackgroundColor) if type(sText) ~= "string" then expect(1, sText, "string") end if type(sTextColor) ~= "string" then expect(2, sTextColor, "string") end if type(sBackgroundColor) ~= "string" then expect(3, sBackgroundColor, "string") end if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then - error( "Arguments must be the same length", 2 ) + error("Arguments must be the same length", 2) end - internalBlit( sText, sTextColor, sBackgroundColor ) + internalBlit(sText, sTextColor, sBackgroundColor) end function window.clear() local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] for y = 1, nHeight do tLines[y] = { text = sEmptyText, @@ -221,15 +272,15 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) function window.clearLine() if nCursorY >= 1 and nCursorY <= nHeight then local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] - tLines[ nCursorY ] = { + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] + tLines[nCursorY] = { text = sEmptyText, textColor = sEmptyTextColor, backgroundColor = sEmptyBackgroundColor, } if bVisible then - redrawLine( nCursorY ) + redrawLine(nCursorY) updateCursorColor() updateCursorPos() end @@ -240,17 +291,17 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return nCursorX, nCursorY end - function window.setCursorPos( x, y ) + function window.setCursorPos(x, y) if type(x) ~= "number" then expect(1, x, "number") end if type(y) ~= "number" then expect(2, y, "number") end - nCursorX = math.floor( x ) - nCursorY = math.floor( y ) + nCursorX = math.floor(x) + nCursorY = math.floor(y) if bVisible then updateCursorPos() end end - function window.setCursorBlink( blink ) + function window.setCursorBlink(blink) if type(blink) ~= "boolean" then expect(1, blink, "boolean") end bCursorBlink = blink if bVisible then @@ -274,10 +325,10 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return isColor() end - local function setTextColor( color ) + local function setTextColor(color) if type(color) ~= "number" then expect(1, color, "number") end if tHex[color] == nil then - error( "Invalid color (got " .. color .. ")" , 2 ) + error("Invalid color (got " .. color .. ")" , 2) end nTextColor = color @@ -289,50 +340,50 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) window.setTextColor = setTextColor window.setTextColour = setTextColor - function window.setPaletteColour( colour, r, g, b ) + function window.setPaletteColour(colour, r, g, b) if type(colour) ~= "number" then expect(1, colour, "number") end if tHex[colour] == nil then - error( "Invalid color (got " .. colour .. ")" , 2 ) + error("Invalid color (got " .. colour .. ")" , 2) end local tCol if type(r) == "number" and g == nil and b == nil then - tCol = { colours.unpackRGB( r ) } - tPalette[ colour ] = tCol + tCol = { colours.unpackRGB(r) } + tPalette[colour] = tCol else if type(r) ~= "number" then expect(2, r, "number") end if type(g) ~= "number" then expect(3, g, "number") end if type(b) ~= "number" then expect(4, b, "number") end - tCol = tPalette[ colour ] + tCol = tPalette[colour] tCol[1] = r tCol[2] = g tCol[3] = b end if bVisible then - return parent.setPaletteColour( colour, tCol[1], tCol[2], tCol[3] ) + return parent.setPaletteColour(colour, tCol[1], tCol[2], tCol[3]) end end window.setPaletteColor = window.setPaletteColour - function window.getPaletteColour( colour ) + function window.getPaletteColour(colour) if type(colour) ~= "number" then expect(1, colour, "number") end if tHex[colour] == nil then - error( "Invalid color (got " .. colour .. ")" , 2 ) + error("Invalid color (got " .. colour .. ")" , 2) end - local tCol = tPalette[ colour ] + local tCol = tPalette[colour] return tCol[1], tCol[2], tCol[3] end window.getPaletteColor = window.getPaletteColour - local function setBackgroundColor( color ) + local function setBackgroundColor(color) if type(color) ~= "number" then expect(1, color, "number") end if tHex[color] == nil then - error( "Invalid color (got " .. color .. ")", 2 ) + error("Invalid color (got " .. color .. ")", 2) end nBackgroundColor = color end @@ -344,13 +395,13 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return nWidth, nHeight end - function window.scroll( n ) + function window.scroll(n) if type(n) ~= "number" then expect(1, n, "number") end if n ~= 0 then local tNewLines = {} local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] for newY = 1, nHeight do local y = newY + n if y >= 1 and y <= nHeight then @@ -388,6 +439,13 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return nBackgroundColor end + --- Get the buffered contents of a line in this window. + --- + -- @tparam number y The y position of the line to get. + -- @treturn string The textual content of this line. + -- @treturn string The text colours of this line, suitable for use with @{term.blit}. + -- @treturn string The background colours of this line, suitable for use with @{term.blit}. + -- @throws If `y` is not between 1 and this window's height. function window.getLine(y) if type(y) ~= "number" then expect(1, y, "number") end @@ -399,16 +457,26 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end -- Other functions - function window.setVisible( bVis ) - if type(bVis) ~= "boolean" then expect(1, bVis, "boolean") end - if bVisible ~= bVis then - bVisible = bVis + + --- Set whether this window is visible. Invisible windows will not be drawn + -- to the screen until they are made visible again. + -- + -- Making an invisible window visible will immediately draw it. + -- + -- @tparam boolean visible Whether this window is visible. + function window.setVisible(visible) + if type(visible) ~= "boolean" then expect(1, visible, "boolean") end + if bVisible ~= visible then + bVisible = visible if bVisible then window.redraw() end end end + --- Draw this window. This does nothing if the window is not visible. + -- + -- @see Window:setVisible function window.redraw() if bVisible then redraw() @@ -419,6 +487,8 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end end + --- Set the current terminal's cursor to where this window's cursor is. This + -- does nothing if the window is not visible. function window.restoreCursor() if bVisible then updateCursorBlink() @@ -427,31 +497,47 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end end + --- Get the position of the top left corner of this window. + -- + -- @treturn number The x position of this window. + -- @treturn number The y position of this window. function window.getPosition() return nX, nY end - function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight, newParent ) - if type(nNewX) ~= "number" then expect(1, nNewX, "number") end - if type(nNewY) ~= "number" then expect(2, nNewY, "number") end - if nNewWidth ~= nil or nNewHeight ~= nil then - expect(3, nNewWidth, "number") - expect(4, nNewHeight, "number") + --- Reposition or resize the given window. + -- + -- This function also accepts arguments to change the size of this window. + -- It is recommended that you fire a `term_resize` event after changing a + -- window's, to allow programs to adjust their sizing. + -- + -- @tparam number new_x The new x position of this window. + -- @tparam number new_y The new y position of this window. + -- @tparam[opt] number new_width The new width of this window. + -- @tparam number new_height The new height of this window. + -- @tparam[opt] term.Redirect new_parent The new redirect object this + -- window should draw to. + function window.reposition(new_x, new_y, new_width, new_height, new_parent) + if type(new_x) ~= "number" then expect(1, new_x, "number") end + if type(new_y) ~= "number" then expect(2, new_y, "number") end + if new_width ~= nil or new_height ~= nil then + expect(3, new_width, "number") + expect(4, new_height, "number") end - if newParent ~= nil and type(newParent) ~= "table" then expect(5, newParent, "table") end + if new_parent ~= nil and type(new_parent) ~= "table" then expect(5, new_parent, "table") end - nX = nNewX - nY = nNewY + nX = new_x + nY = new_y - if newParent then parent = newParent end + if new_parent then parent = new_parent end - if nNewWidth and nNewHeight then + if new_width and new_height then local tNewLines = {} - createEmptyLines( nNewWidth ) + createEmptyLines(new_width) local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] - for y = 1, nNewHeight do + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] + for y = 1, new_height do if y > nHeight then tNewLines[y] = { text = sEmptyText, @@ -460,25 +546,25 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) } else local tOldLine = tLines[y] - if nNewWidth == nWidth then + if new_width == nWidth then tNewLines[y] = tOldLine - elseif nNewWidth < nWidth then + elseif new_width < nWidth then tNewLines[y] = { - text = string_sub( tOldLine.text, 1, nNewWidth ), - textColor = string_sub( tOldLine.textColor, 1, nNewWidth ), - backgroundColor = string_sub( tOldLine.backgroundColor, 1, nNewWidth ), + text = string_sub(tOldLine.text, 1, new_width), + textColor = string_sub(tOldLine.textColor, 1, new_width), + backgroundColor = string_sub(tOldLine.backgroundColor, 1, new_width), } else tNewLines[y] = { - text = tOldLine.text .. string_sub( sEmptyText, nWidth + 1, nNewWidth ), - textColor = tOldLine.textColor .. string_sub( sEmptyTextColor, nWidth + 1, nNewWidth ), - backgroundColor = tOldLine.backgroundColor .. string_sub( sEmptyBackgroundColor, nWidth + 1, nNewWidth ), + text = tOldLine.text .. string_sub(sEmptyText, nWidth + 1, new_width), + textColor = tOldLine.textColor .. string_sub(sEmptyTextColor, nWidth + 1, new_width), + backgroundColor = tOldLine.backgroundColor .. string_sub(sEmptyBackgroundColor, nWidth + 1, new_width), } end end end - nWidth = nNewWidth - nHeight = nNewHeight + nWidth = new_width + nHeight = new_height tLines = tNewLines end if bVisible then diff --git a/src/main/resources/data/computercraft/lua/rom/help/adventure.txt b/src/main/resources/data/computercraft/lua/rom/help/adventure.txt index bd1d982cf..6a9880eba 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/adventure.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/adventure.txt @@ -1 +1 @@ -adventure is a text adventure game for CraftOS. To navigate around the world of adventure, type simple instructions to the interpreter, for example: "go north", "punch tree", "craft planks", "mine coal with pickaxe", "hit creeper with sword" \ No newline at end of file +adventure is a text adventure game for CraftOS. To navigate around the world of adventure, type simple instructions to the interpreter, for example: "go north", "punch tree", "craft planks", "mine coal with pickaxe", "hit creeper with sword" diff --git a/src/main/resources/data/computercraft/lua/rom/help/alias.txt b/src/main/resources/data/computercraft/lua/rom/help/alias.txt index 4d11d45ce..8f742bd3f 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/alias.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/alias.txt @@ -3,4 +3,4 @@ alias assigns shell commands to run other programs. ex: "alias dir ls" will make the "dir" command run the "ls" program "alias dir" will remove the alias set on "dir" -"alias" will list all current aliases. \ No newline at end of file +"alias" will list all current aliases. diff --git a/src/main/resources/data/computercraft/lua/rom/help/chat.txt b/src/main/resources/data/computercraft/lua/rom/help/chat.txt index 1e99ca45c..035cb463d 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/chat.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/chat.txt @@ -2,4 +2,4 @@ Surf the rednet superhighway with "chat", the networked chat program for CraftOS ex: "chat host forgecraft" will create a chatroom with the name "forgecraft" -"chat join forgecraft direwolf20" will connect to the chatroom with the name "forgecraft", using the nickname "direwolf20" \ No newline at end of file +"chat join forgecraft direwolf20" will connect to the chatroom with the name "forgecraft", using the nickname "direwolf20" diff --git a/src/main/resources/data/computercraft/lua/rom/help/clear.txt b/src/main/resources/data/computercraft/lua/rom/help/clear.txt index ea517ddb3..6e3258411 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/clear.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/clear.txt @@ -1 +1 @@ -clear clears the screen. \ No newline at end of file +clear clears the screen. diff --git a/src/main/resources/data/computercraft/lua/rom/help/coroutine.txt b/src/main/resources/data/computercraft/lua/rom/help/coroutine.txt index 12b366bd2..93d8f7b04 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/coroutine.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/coroutine.txt @@ -1,2 +1,2 @@ coroutine is a standard Lua5.1 API. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/data/computercraft/lua/rom/help/dance.txt b/src/main/resources/data/computercraft/lua/rom/help/dance.txt index 3c776f8f0..cef419ab9 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/dance.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/dance.txt @@ -1 +1 @@ -dance is a program for Turtles. Turtles love to get funky. \ No newline at end of file +dance is a program for Turtles. Turtles love to get funky. diff --git a/src/main/resources/data/computercraft/lua/rom/help/disk.txt b/src/main/resources/data/computercraft/lua/rom/help/disk.txt index f47bc625c..3c1348e6b 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/disk.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/disk.txt @@ -14,4 +14,4 @@ disk.getID( drive ) Events fired by the disk API: "disk" when a disk or other item is inserted into a disk drive. Argument is the name of the drive "disk_eject" when a disk is removed from a disk drive. Argument is the name of the drive -Type "help events" to learn about the event system. \ No newline at end of file +Type "help events" to learn about the event system. diff --git a/src/main/resources/data/computercraft/lua/rom/help/dj.txt b/src/main/resources/data/computercraft/lua/rom/help/dj.txt index 2c7a02bd1..c41dccc6e 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/dj.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/dj.txt @@ -3,4 +3,4 @@ dj plays Music Discs from disk drives attached to the computer. ex: "dj" or "dj play" plays a random disc. "dj play left" plays the disc in the drive on the left of the computer. -"dj stop" stops the current disc. \ No newline at end of file +"dj stop" stops the current disc. diff --git a/src/main/resources/data/computercraft/lua/rom/help/drive.txt b/src/main/resources/data/computercraft/lua/rom/help/drive.txt index 397c98c30..eb6472a8e 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/drive.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/drive.txt @@ -2,4 +2,4 @@ drive tells you which disk drive the current or specified directory is located i ex: "drive" tell you the disk drive of the current directory. -"drive foo" tells you the disk drive of the subdirectory "foo" \ No newline at end of file +"drive foo" tells you the disk drive of the subdirectory "foo" diff --git a/src/main/resources/data/computercraft/lua/rom/help/drives.txt b/src/main/resources/data/computercraft/lua/rom/help/drives.txt index 6f15f40f3..b793f8e7d 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/drives.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/drives.txt @@ -16,4 +16,4 @@ getDiskID() Events fired by the Disk Drive: "disk" when a disk or other item is inserted into the drive. Argument is the name of the drive. "disk_eject" when a disk is removed from a drive. Argument is the name of the drive. -Type "help events" to learn about the event system. \ No newline at end of file +Type "help events" to learn about the event system. diff --git a/src/main/resources/data/computercraft/lua/rom/help/earth.txt b/src/main/resources/data/computercraft/lua/rom/help/earth.txt index d1b452673..b9842d064 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/earth.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/earth.txt @@ -1 +1 @@ -Mostly harmless. \ No newline at end of file +Mostly harmless. diff --git a/src/main/resources/data/computercraft/lua/rom/help/edit.txt b/src/main/resources/data/computercraft/lua/rom/help/edit.txt index 31d044496..6e89a7e08 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/edit.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/edit.txt @@ -1,4 +1,4 @@ edit is a text editor for creating or modifying programs or text files. After creating a program with edit, type its filename in the shell to run it. You can open any of the builtin programs with edit to learn how to program. ex: -"edit hello" opens a file called "hello" for editing. \ No newline at end of file +"edit hello" opens a file called "hello" for editing. diff --git a/src/main/resources/data/computercraft/lua/rom/help/exit.txt b/src/main/resources/data/computercraft/lua/rom/help/exit.txt index 9b6c4347f..891745139 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/exit.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/exit.txt @@ -1 +1 @@ -exit will exit the current shell. \ No newline at end of file +exit will exit the current shell. diff --git a/src/main/resources/data/computercraft/lua/rom/help/gps.txt b/src/main/resources/data/computercraft/lua/rom/help/gps.txt index e3e14b566..35b833580 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/gps.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/gps.txt @@ -4,7 +4,7 @@ Type "help gpsapi" for help using GPS functions in lua programs. ex: "gps locate" will connect to nearby GPS servers, and try to determine the position of the computer or turtle. "gps host" will try to determine the position, and host a GPS server if successful. -"gps host 10 20 30" will host a GPS server, using the manually entered position 10,20,30. +"gps host 10 20 30" will host a GPS server, using the manually entered position 10,20,30. Take care when manually entering host positions. If the positions entered into multiple GPS hosts -are not consistent, the results of locate calls will be incorrect. \ No newline at end of file +are not consistent, the results of locate calls will be incorrect. diff --git a/src/main/resources/data/computercraft/lua/rom/help/gpsapi.txt b/src/main/resources/data/computercraft/lua/rom/help/gpsapi.txt index 7bb9fe601..83116f669 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/gpsapi.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/gpsapi.txt @@ -1,4 +1,4 @@ Functions in the GPS API: gps.locate( timeout ) -The locate function will send a signal to nearby gps servers, and wait for responses before the timeout. If it receives enough responses to determine this computers position then x, y and z co-ordinates will be returned, otherwise it will return nil. If GPS hosts do not have their positions configured correctly, results will be inaccurate. \ No newline at end of file +The locate function will send a signal to nearby gps servers, and wait for responses before the timeout. If it receives enough responses to determine this computers position then x, y and z co-ordinates will be returned, otherwise it will return nil. If GPS hosts do not have their positions configured correctly, results will be inaccurate. diff --git a/src/main/resources/data/computercraft/lua/rom/help/hello.txt b/src/main/resources/data/computercraft/lua/rom/help/hello.txt index a58ae9908..0f2017aad 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/hello.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/hello.txt @@ -1 +1 @@ -hello prints the text "Hello World!" to the screen. \ No newline at end of file +hello prints the text "Hello World!" to the screen. diff --git a/src/main/resources/data/computercraft/lua/rom/help/help.txt b/src/main/resources/data/computercraft/lua/rom/help/help.txt index fe85a2370..29c0b3a32 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/help.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/help.txt @@ -1,4 +1,4 @@ help is the help tool you're currently using. Type "help index" to see all help topics. Type "help" to see the help intro. -Type "help helpapi" for information on the help Lua API. \ No newline at end of file +Type "help helpapi" for information on the help Lua API. diff --git a/src/main/resources/data/computercraft/lua/rom/help/id.txt b/src/main/resources/data/computercraft/lua/rom/help/id.txt index f87492bee..e23f1290a 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/id.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/id.txt @@ -2,4 +2,4 @@ id prints the unique identifier of this computer, or a Disk in an attached Disk ex: "id" will print this Computers ID and label -"id left" will print the ID and label of the disk in the Disk Drive on the left \ No newline at end of file +"id left" will print the ID and label of the disk in the Disk Drive on the left diff --git a/src/main/resources/data/computercraft/lua/rom/help/io.txt b/src/main/resources/data/computercraft/lua/rom/help/io.txt index f71cca207..8da72cbd1 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/io.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/io.txt @@ -1,2 +1,2 @@ io is a standard Lua5.1 API, reimplemented for CraftOS. Not all the features are availiable. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/data/computercraft/lua/rom/help/keys.txt b/src/main/resources/data/computercraft/lua/rom/help/keys.txt index 0adb2016c..a46f10731 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/keys.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/keys.txt @@ -3,7 +3,7 @@ The keys API contains constants for all the key codes that can be returned by th Example usage: local sEvent, nKey = os.pullEvent() if sEvent == "key" and nKey == keys.enter then - -- Do something + -- Do something end -See http://www.minecraftwiki.net/wiki/Key_codes, or the source code, for a complete reference. \ No newline at end of file +See http://www.minecraftwiki.net/wiki/Key_codes, or the source code, for a complete reference. diff --git a/src/main/resources/data/computercraft/lua/rom/help/list.txt b/src/main/resources/data/computercraft/lua/rom/help/list.txt index 9ab8cd06c..16c0fdf52 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/list.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/list.txt @@ -1 +1 @@ -ls will list all the directories and files in the current location. Use "type" to find out if an item is a file or a directory. \ No newline at end of file +ls will list all the directories and files in the current location. Use "type" to find out if an item is a file or a directory. diff --git a/src/main/resources/data/computercraft/lua/rom/help/lua.txt b/src/main/resources/data/computercraft/lua/rom/help/lua.txt index da1cb187a..4d164c8b0 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/lua.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/lua.txt @@ -1 +1 @@ -lua is an interactive prompt for the lua programming language. It's a useful tool for learning the language. \ No newline at end of file +lua is an interactive prompt for the lua programming language. It's a useful tool for learning the language. diff --git a/src/main/resources/data/computercraft/lua/rom/help/math.txt b/src/main/resources/data/computercraft/lua/rom/help/math.txt index ed3da1e49..35ed34827 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/math.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/math.txt @@ -1,2 +1,2 @@ math is a standard Lua5.1 API. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/data/computercraft/lua/rom/help/mkdir.txt b/src/main/resources/data/computercraft/lua/rom/help/mkdir.txt index e7268dc63..e5e8fdab3 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/mkdir.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/mkdir.txt @@ -2,4 +2,4 @@ mkdir creates a directory in the current location. ex: "mkdir foo" creates a directory named "foo". -"mkdir ../foo" creates a directory named "foo" in the directory above the current directory. \ No newline at end of file +"mkdir ../foo" creates a directory named "foo" in the directory above the current directory. diff --git a/src/main/resources/data/computercraft/lua/rom/help/modems.txt b/src/main/resources/data/computercraft/lua/rom/help/modems.txt index 960bc5058..281a87582 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/modems.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/modems.txt @@ -9,4 +9,4 @@ transmit( channel, replyChannel, message ) isWireless() Events fired by Modems: -"modem_message" when a message is received on an open channel. Arguments are name, channel, replyChannel, message, distance \ No newline at end of file +"modem_message" when a message is received on an open channel. Arguments are name, channel, replyChannel, message, distance diff --git a/src/main/resources/data/computercraft/lua/rom/help/monitor.txt b/src/main/resources/data/computercraft/lua/rom/help/monitor.txt index 6837b38d4..028a8bc80 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/monitor.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/monitor.txt @@ -3,4 +3,4 @@ Type "help monitors" for help using monitors as peripherals in lua programs. ex: "monitor left hello" will run the "hello" program on the monitor to the left of the computer. -"monitor top edit foo" will run the edit program on the top monitor, editing the file "foo". \ No newline at end of file +"monitor top edit foo" will run the edit program on the top monitor, editing the file "foo". diff --git a/src/main/resources/data/computercraft/lua/rom/help/multishell.txt b/src/main/resources/data/computercraft/lua/rom/help/multishell.txt index b16243112..8fbf8d75b 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/multishell.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/multishell.txt @@ -1,2 +1,2 @@ multishell is the toplevel program on Advanced Computers which manages background tabs. -Type "help shellapi" for information about the shell lua api. \ No newline at end of file +Type "help shellapi" for information about the shell lua api. diff --git a/src/main/resources/data/computercraft/lua/rom/help/os.txt b/src/main/resources/data/computercraft/lua/rom/help/os.txt index 442d4a89b..b57bef8da 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/os.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/os.txt @@ -23,4 +23,4 @@ os.reboot() Events emitted by the os API: "timer" when a timeout started by os.startTimer() completes. Argument is the token returned by os.startTimer(). "alarm" when a time passed to os.setAlarm() is reached. Argument is the token returned by os.setAlarm(). -Type "help events" to learn about the event system. \ No newline at end of file +Type "help events" to learn about the event system. diff --git a/src/main/resources/data/computercraft/lua/rom/help/parallel.txt b/src/main/resources/data/computercraft/lua/rom/help/parallel.txt index 822dd47a7..4b958c442 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/parallel.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/parallel.txt @@ -1,4 +1,4 @@ Functions in the Parallel API: parallel.waitForAny( function1, function2, ... ) parallel.waitForAll( function1, function2, ... ) -These methods provide an easy way to run multiple lua functions simultaneously. \ No newline at end of file +These methods provide an easy way to run multiple lua functions simultaneously. diff --git a/src/main/resources/data/computercraft/lua/rom/help/pocket.txt b/src/main/resources/data/computercraft/lua/rom/help/pocket.txt index fc498c669..72925bdea 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/pocket.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/pocket.txt @@ -3,4 +3,4 @@ Functions in the pocket API: pocket.equipBack() pocket.unequipBack() -When equipping upgrades, it will search your inventory for a suitable upgrade, starting in the selected slot. If one cannot be found then it will check your offhand. \ No newline at end of file +When equipping upgrades, it will search your inventory for a suitable upgrade, starting in the selected slot. If one cannot be found then it will check your offhand. diff --git a/src/main/resources/data/computercraft/lua/rom/help/printers.txt b/src/main/resources/data/computercraft/lua/rom/help/printers.txt index a855ab972..73295344e 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/printers.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/printers.txt @@ -9,4 +9,4 @@ getPageSize() setCursorPos( x, y ) getCursorPos() write( text ) -endPage() \ No newline at end of file +endPage() diff --git a/src/main/resources/data/computercraft/lua/rom/help/programming.txt b/src/main/resources/data/computercraft/lua/rom/help/programming.txt index 68e8621fc..4a14fb2e3 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/programming.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/programming.txt @@ -8,4 +8,4 @@ To quickly shutdown a computer, hold Ctrl+S for 1 second. To quickly reboot a computer, hold Ctrl+R for 1 second. To learn about the programming APIs availiable, type "apis" or "help apis". -If you get stuck, visit the forums at http://www.computercraft.info/ for advice and tutorials. \ No newline at end of file +If you get stuck, visit the forums at http://www.computercraft.info/ for advice and tutorials. diff --git a/src/main/resources/data/computercraft/lua/rom/help/reboot.txt b/src/main/resources/data/computercraft/lua/rom/help/reboot.txt index 6cae9184d..525c9c979 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/reboot.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/reboot.txt @@ -1,2 +1,2 @@ reboot will turn the computer off and on again. -You can also hold Ctrl+R at any time to quickly reboot. \ No newline at end of file +You can also hold Ctrl+R at any time to quickly reboot. diff --git a/src/main/resources/data/computercraft/lua/rom/help/redstone.txt b/src/main/resources/data/computercraft/lua/rom/help/redstone.txt index ea76f7827..ce86bb6b4 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/redstone.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/redstone.txt @@ -6,4 +6,4 @@ ex: "redstone set right blue false" turns off the blue wire in the bundled cable on the right redstone output. "redstone pulse front 10 1" emits 10 one second redstone pulses on the front redstone output. -Type "help redstoneapi" or "help rs" for information on the redstone Lua API. \ No newline at end of file +Type "help redstoneapi" or "help rs" for information on the redstone Lua API. diff --git a/src/main/resources/data/computercraft/lua/rom/help/refuel.txt b/src/main/resources/data/computercraft/lua/rom/help/refuel.txt index 9fab3fa18..86e806b2c 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/refuel.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/refuel.txt @@ -3,4 +3,4 @@ refuel is a program for Turtles. Refuel will consume items from the inventory as ex: "refuel" will refuel with at most one fuel item "refuel 10" will refuel with at most 10 fuel items -"refuel all" will refuel with as many fuel items as possible \ No newline at end of file +"refuel all" will refuel with as many fuel items as possible diff --git a/src/main/resources/data/computercraft/lua/rom/help/repeat.txt b/src/main/resources/data/computercraft/lua/rom/help/repeat.txt index f65697d4a..a08ebf8da 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/repeat.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/repeat.txt @@ -1 +1 @@ -repeat is a program for repeating rednet messages across long distances. To use, connect 2 or more modems to a computer and run the "repeat" program; from then on, any rednet message sent from any computer in wireless range or connected by networking cable to either of the modems will be repeated to those on the other side. \ No newline at end of file +repeat is a program for repeating rednet messages across long distances. To use, connect 2 or more modems to a computer and run the "repeat" program; from then on, any rednet message sent from any computer in wireless range or connected by networking cable to either of the modems will be repeated to those on the other side. diff --git a/src/main/resources/data/computercraft/lua/rom/help/shell.txt b/src/main/resources/data/computercraft/lua/rom/help/shell.txt index 080b8390a..9be848561 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/shell.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/shell.txt @@ -1,2 +1,2 @@ shell is the toplevel program which interprets commands and runs program. -Type "help shellapi" for information about the shell lua api. \ No newline at end of file +Type "help shellapi" for information about the shell lua api. diff --git a/src/main/resources/data/computercraft/lua/rom/help/shutdown.txt b/src/main/resources/data/computercraft/lua/rom/help/shutdown.txt index 4a63391db..8bc734fc9 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/shutdown.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/shutdown.txt @@ -1 +1 @@ -shutdown will turn off the computer. \ No newline at end of file +shutdown will turn off the computer. diff --git a/src/main/resources/data/computercraft/lua/rom/help/string.txt b/src/main/resources/data/computercraft/lua/rom/help/string.txt index 5dfe5d501..ce30dc916 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/string.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/string.txt @@ -1,2 +1,2 @@ string is a standard Lua5.1 API. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/data/computercraft/lua/rom/help/table.txt b/src/main/resources/data/computercraft/lua/rom/help/table.txt index 80760d0de..d6943d035 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/table.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/table.txt @@ -1,2 +1,2 @@ table is a standard Lua5.1 API. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/data/computercraft/lua/rom/help/time.txt b/src/main/resources/data/computercraft/lua/rom/help/time.txt index ae5113599..4a67ab57d 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/time.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/time.txt @@ -1 +1 @@ -time prints the current time of day. \ No newline at end of file +time prints the current time of day. diff --git a/src/main/resources/data/computercraft/lua/rom/help/type.txt b/src/main/resources/data/computercraft/lua/rom/help/type.txt index 74a4e8e79..1c8cad512 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/type.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/type.txt @@ -1 +1 @@ -type determines the type of a file or directory. Prints "file", "directory" or "does not exist". \ No newline at end of file +type determines the type of a file or directory. Prints "file", "directory" or "does not exist". diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua index 7b1a53e8c..24ca66d56 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua @@ -5,28 +5,29 @@ local native_select, native_type = select, type ---- Expect an argument to have a specific type. --- --- @tparam int index The 1-based argument index. --- @param value The argument's value. --- @tparam string ... The allowed types of the argument. --- @throws If the value is not one of the allowed types. -local function expect(index, value, ...) - local t = native_type(value) - for i = 1, native_select("#", ...) do - if t == native_select(i, ...) then return true end - end - +local function get_type_names(...) local types = table.pack(...) for i = types.n, 1, -1 do if types[i] == "nil" then table.remove(types, i) end end - local type_names if #types <= 1 then - type_names = tostring(...) + return tostring(...) else - type_names = table.concat(types, ", ", 1, #types - 1) .. " or " .. types[#types] + return table.concat(types, ", ", 1, #types - 1) .. " or " .. types[#types] + end +end +--- Expect an argument to have a specific type. +-- +-- @tparam number index The 1-based argument index. +-- @param value The argument's value. +-- @tparam string ... The allowed types of the argument. +-- @return The given `value`. +-- @throws If the value is not one of the allowed types. +local function expect(index, value, ...) + local t = native_type(value) + for i = 1, native_select("#", ...) do + if t == native_select(i, ...) then return value end end -- If we can determine the function name with a high level of confidence, try to include it. @@ -36,11 +37,39 @@ local function expect(index, value, ...) if ok and info.name and #info.name ~= "" and info.what ~= "C" then name = info.name end end + local type_names = get_type_names(...) if name then - error( ("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3 ) + error(("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3) else - error( ("bad argument #%d (expected %s, got %s)"):format(index, type_names, t), 3 ) + error(("bad argument #%d (expected %s, got %s)"):format(index, type_names, t), 3) end end -return { expect = expect } +--- Expect an field to have a specific type. +-- +-- @tparam table tbl The table to index. +-- @tparam string index The field name to check. +-- @tparam string ... The allowed types of the argument. +-- @return The contents of the given field. +-- @throws If the field is not one of the allowed types. +local function field(tbl, index, ...) + expect(1, tbl, "table") + expect(2, index, "string") + + local value = tbl[index] + local t = native_type(value) + for i = 1, native_select("#", ...) do + if t == native_select(i, ...) then return value end + end + + if value == nil then + error(("field '%s' missing from table"):format(index), 3) + else + error(("bad field '%s' (expected %s, got %s)"):format(index, get_type_names(...), t), 3) + end +end + +return { + expect = expect, + field = field, +} diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua new file mode 100644 index 000000000..95b0c76fa --- /dev/null +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -0,0 +1,419 @@ +--- Provides a "pretty printer", for rendering data structures in an +-- aesthetically pleasing manner. +-- +-- In order to display something using @{cc.pretty}, you build up a series of +-- @{Doc|documents}. These behave a little bit like strings; you can concatenate +-- them together and then print them to the screen. +-- +-- However, documents also allow you to control how they should be printed. There +-- are several functions (such as @{nest} and @{group}) which allow you to control +-- the "layout" of the document. When you come to display the document, the 'best' +-- (most compact) layout is used. +-- +-- @module cc.pretty +-- @usage Print a table to the terminal +-- local pretty = require "cc.pretty" +-- pretty.write(pretty.dump({ 1, 2, 3 })) +-- +-- @usage Build a custom document and display it +-- local pretty = require "cc.pretty" +-- pretty.write(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world"))) + +local expect = require "cc.expect".expect +local type, getmetatable, setmetatable, colours, str_write = type, getmetatable, setmetatable, colours, write + +--- @{table.insert} alternative, but with the length stored inline. +local function append(out, value) + local n = out.n + 1 + out[n], out.n = value, n +end + +--- A document containing formatted text, with multiple possible layouts. +-- +-- Documents effectively represent a sequence of strings in alternative layouts, +-- which we will try to print in the most compact form necessary. +-- +-- @type Doc +local Doc = { } + +--- An empty document. +local empty = setmetatable({ tag = "nil" }, Doc) + +--- A document with a single space in it. +local space = setmetatable({ tag = "text", text = " " }, Doc) + +--- A line break. When collapsed with @{group}, this will be replaced with @{empty}. +local line = setmetatable({ tag = "line", flat = empty }, Doc) + +--- A line break. When collapsed with @{group}, this will be replaced with @{space}. +local space_line = setmetatable({ tag = "line", flat = space }, Doc) + +local text_cache = { [""] = empty, [" "] = space, ["\n"] = space_line } + +local function mk_text(text, colour) + return text_cache[text] or setmetatable({ tag = "text", text = text, colour = colour }, Doc) +end + +--- Create a new document from a string. +-- +-- If your string contains multiple lines, @{group} will flatten the string +-- into a single line, with spaces between each line. +-- +-- @tparam string text The string to construct a new document with. +-- @tparam[opt] number colour The colour this text should be printed with. If not given, we default to the current +-- colour. +-- @treturn Doc The document with the provided text. +local function text(text, colour) + expect(1, text, "string") + expect(2, colour, "number", "nil") + + local cached = text_cache[text] + if cached then return cached end + + local new_line = text:find("\n", 1) + if not new_line then return mk_text(text, colour) end + + -- Split the string by "\n". With a micro-optimisation to skip empty strings. + local doc = setmetatable({ tag = "concat", n = 0 }, Doc) + if new_line ~= 1 then append(doc, mk_text(text:sub(1, new_line - 1), colour)) end + + new_line = new_line + 1 + while true do + local next_line = text:find("\n", new_line) + append(doc, space_line) + if not next_line then + if new_line <= #text then append(doc, mk_text(text:sub(new_line), colour)) end + return doc + else + if new_line <= next_line - 1 then + append(doc, mk_text(text:sub(new_line, next_line - 1), colour)) + end + new_line = next_line + 1 + end + end +end + +--- Concatenate several documents together. This behaves very similar to string concatenation. +-- +-- @tparam Doc|string ... The documents to concatenate. +-- @treturn Doc The concatenated documents. +-- @usage pretty.concat(doc1, " - ", doc2) +-- @usage doc1 .. " - " .. doc2 +local function concat(...) + local args = table.pack(...) + for i = 1, args.n do + if type(args[i]) == "string" then args[i] = text(args[i]) end + if getmetatable(args[i]) ~= Doc then expect(i, args[i], "document") end + end + + if args.n == 0 then return empty end + if args.n == 1 then return args[1] end + + args.tag = "concat" + return setmetatable(args, Doc) +end + +Doc.__concat = concat --- @local + +--- Indent later lines of the given document with the given number of spaces. +-- +-- For instance, nesting the document +-- ```txt +-- foo +-- bar +-- ``` +-- by two spaces will produce +-- ```txt +-- foo +-- bar +-- ``` +-- +-- @tparam number depth The number of spaces with which the document should be indented. +-- @tparam Doc doc The document to indent. +-- @treturn Doc The nested document. +-- @usage pretty.nest(2, pretty.text("foo\nbar")) +local function nest(depth, doc) + expect(1, depth, "number") + if getmetatable(doc) ~= Doc then expect(2, doc, "document") end + if depth <= 0 then error("depth must be a positive number", 2) end + + return setmetatable({ tag = "nest", depth = depth, doc }, Doc) +end + +local function flatten(doc) + if doc.flat then return doc.flat end + + local kind = doc.tag + if kind == "nil" or kind == "text" then + return doc + elseif kind == "concat" then + local out = setmetatable({ tag = "concat", n = doc.n }, Doc) + for i = 1, doc.n do out[i] = flatten(doc[i]) end + doc.flat, out.flat = out, out -- cache the flattened node + return out + elseif kind == "nest" then + return flatten(doc[1]) + elseif kind == "group" then + return doc[1] + else + error("Unknown doc " .. kind) + end +end + +--- Builds a document which is displayed on a single line if there is enough +-- room, or as normal if not. +-- +-- @tparam Doc doc The document to group. +-- @treturn Doc The grouped document. +local function group(doc) + if getmetatable(doc) ~= Doc then expect(1, doc, "document") end + + if doc.tag == "group" then return doc end -- Skip if already grouped. + + local flattened = flatten(doc) + if flattened == doc then return doc end -- Also skip if flattening does nothing. + return setmetatable({ tag = "group", flattened, doc }, Doc) +end + +local function get_remaining(doc, width) + local kind = doc.tag + if kind == "nil" or kind == "line" then + return width + elseif kind == "text" then + return width - #doc.text + elseif kind == "concat" then + for i = 1, doc.n do + width = get_remaining(doc[i], width) + if width < 0 then break end + end + return width + elseif kind == "group" or kind == "nest" then + return get_remaining(kind[1]) + else + error("Unknown doc " .. kind) + end +end + +--- Display a document on the terminal. +-- +-- @tparam Doc doc The document to render +-- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in. +local function write(doc, ribbon_frac) + if getmetatable(doc) ~= Doc then expect(1, doc, "document") end + expect(2, ribbon_frac, "number", "nil") + + local term = term + local width, height = term.getSize() + local ribbon_width = (ribbon_frac or 0.6) * width + if ribbon_width < 0 then ribbon_width = 0 end + if ribbon_width > width then ribbon_width = width end + + local def_colour = term.getTextColour() + local current_colour = def_colour + + local function go(doc, indent, col) + local kind = doc.tag + if kind == "nil" then + return col + elseif kind == "text" then + local doc_colour = doc.colour or def_colour + if doc_colour ~= current_colour then + term.setTextColour(doc_colour) + current_colour = doc_colour + end + + str_write(doc.text) + + return col + #doc.text + elseif kind == "line" then + local _, y = term.getCursorPos() + if y < height then + term.setCursorPos(indent + 1, y + 1) + else + term.scroll(1) + term.setCursorPos(indent + 1, height) + end + + return indent + elseif kind == "concat" then + for i = 1, doc.n do col = go(doc[i], indent, col) end + return col + elseif kind == "nest" then + return go(doc[1], indent + doc.depth, col) + elseif kind == "group" then + if get_remaining(doc[1], math.min(width, ribbon_width + indent) - col) >= 0 then + return go(doc[1], indent, col) + else + return go(doc[2], indent, col) + end + else + error("Unknown doc " .. kind) + end + end + + local col = math.max(term.getCursorPos() - 1, 0) + go(doc, 0, col) + if current_colour ~= def_colour then term.setTextColour(def_colour) end +end + +--- Display a document on the terminal with a trailing new line. +-- +-- @tparam Doc doc The document to render. +-- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in. +local function print(doc, ribbon_frac) + if getmetatable(doc) ~= Doc then expect(1, doc, "document") end + expect(2, ribbon_frac, "number", "nil") + write(doc, ribbon_frac) + str_write("\n") +end + +--- Render a document, converting it into a string. +-- +-- @tparam Doc doc The document to render. +-- @tparam[opt] number width The maximum width of this document. Note that long strings will not be wrapped to +-- fit this width - it is only used for finding the best layout. +-- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in. +-- @treturn string The rendered document as a string. +local function render(doc, width, ribbon_frac) + if getmetatable(doc) ~= Doc then expect(1, doc, "document") end + expect(2, width, "number", "nil") + expect(3, ribbon_frac, "number", "nil") + + local ribbon_width + if width then + ribbon_width = (ribbon_frac or 0.6) * width + if ribbon_width < 0 then ribbon_width = 0 end + if ribbon_width > width then ribbon_width = width end + end + + local out = { n = 0 } + local function go(doc, indent, col) + local kind = doc.tag + if kind == "nil" then + return col + elseif kind == "text" then + append(out, doc.text) + return col + #doc.text + elseif kind == "line" then + append(out, "\n" .. (" "):rep(indent)) + return indent + elseif kind == "concat" then + for i = 1, doc.n do col = go(doc[i], indent, col) end + return col + elseif kind == "nest" then + return go(doc[1], indent + doc.depth, col) + elseif kind == "group" then + if not width or get_remaining(doc[1], math.min(width, ribbon_width + indent) - col) >= 0 then + return go(doc[1], indent, col) + else + return go(doc[2], indent, col) + end + else + error("Unknown doc " .. kind) + end + end + + go(doc, 0, 0) + return table.concat(out, "", 1, out.n) +end + +Doc.__tostring = render --- @local + +local keywords = { + ["and"] = true, ["break"] = true, ["do"] = true, ["else"] = true, + ["elseif"] = true, ["end"] = true, ["false"] = true, ["for"] = true, + ["function"] = true, ["if"] = true, ["in"] = true, ["local"] = true, + ["nil"] = true, ["not"] = true, ["or"] = true, ["repeat"] = true, ["return"] = true, + ["then"] = true, ["true"] = true, ["until"] = true, ["while"] = true, + } + +local comma = text(",") +local braces = text("{}") +local obrace, cbrace = text("{"), text("}") +local obracket, cbracket = text("["), text("] = ") + +local function key_compare(a, b) + local ta, tb = type(a), type(b) + + if ta == "string" then return tb ~= "string" or a < b + elseif tb == "string" then return false + end + + if ta == "number" then return tb ~= "number" or a < b end + return false +end + +local function pretty_impl(obj, tracking) + local obj_type = type(obj) + if obj_type == "string" then + local formatted = ("%q"):format(obj):gsub("\\\n", "\\n") + return text(formatted, colours.red) + elseif obj_type == "number" then + return text(tostring(obj), colours.magenta) + elseif obj_type ~= "table" or tracking[obj] then + return text(tostring(obj), colours.lightGrey) + elseif getmetatable(obj) ~= nil and getmetatable(obj).__tostring then + return text(tostring(obj)) + elseif next(obj) == nil then + return braces + else + tracking[obj] = true + local doc = setmetatable({ tag = "concat", n = 1, space_line }, Doc) + + local length, keys, keysn = #obj, {}, 1 + for k in pairs(obj) do keys[keysn], keysn = k, keysn + 1 end + table.sort(keys, key_compare) + + for i = 1, keysn - 1 do + if i > 1 then append(doc, comma) append(doc, space_line) end + + local k = keys[i] + local v = obj[k] + local ty = type(k) + if ty == "number" and k % 1 == 0 and k >= 1 and k <= length then + append(doc, pretty_impl(v, tracking)) + elseif ty == "string" and not keywords[k] and k:match("^[%a_][%a%d_]*$") then + append(doc, text(k .. " = ")) + append(doc, pretty_impl(v, tracking)) + else + append(doc, obracket) + append(doc, pretty_impl(k, tracking)) + append(doc, cbracket) + append(doc, pretty_impl(v, tracking)) + end + end + + tracking[obj] = nil + return group(concat(obrace, nest(2, concat(table.unpack(doc, 1, n))), space_line, cbrace)) + end +end + +--- Pretty-print an arbitrary object, converting it into a document. +-- +-- This can then be rendered with @{write} or @{print}. +-- +-- @param obj The object to pretty-print. +-- @treturn Doc The object formatted as a document. +-- @usage Display a table on the screen +-- local pretty = require "cc.pretty" +-- pretty.print(pretty.pretty({ 1, 2, 3 })) +local function pretty(obj) + return pretty_impl(obj, {}) +end + +return { + empty = empty, + space = space, + line = line, + space_line = space_line, + text = text, + concat = concat, + nest = nest, + group = group, + + write = write, + print = print, + render = render, + + pretty = pretty, +} diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua index 865e54dcb..d89c72a91 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua @@ -97,7 +97,7 @@ end -- complete.build( -- { complete.choice, { "get", "put" } }, -- complete.dir, --- } complete.file, many = true } +-- { complete.file, many = true } -- ) local function build(...) local arguments = table.pack(...) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/advanced/bg.lua b/src/main/resources/data/computercraft/lua/rom/programs/advanced/bg.lua index 806a128cd..907e9f7aa 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/advanced/bg.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/advanced/bg.lua @@ -1,12 +1,12 @@ if not shell.openTab then - printError( "Requires multishell" ) + printError("Requires multishell") return end local tArgs = { ... } if #tArgs > 0 then - shell.openTab( table.unpack( tArgs ) ) + shell.openTab(table.unpack(tArgs)) else - shell.openTab( "shell" ) + shell.openTab("shell") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/advanced/fg.lua b/src/main/resources/data/computercraft/lua/rom/programs/advanced/fg.lua index 754fdbf8e..efc7832eb 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/advanced/fg.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/advanced/fg.lua @@ -1,18 +1,18 @@ if not shell.openTab then - printError( "Requires multishell" ) + printError("Requires multishell") return end local tArgs = { ... } if #tArgs > 0 then - local nTask = shell.openTab( table.unpack( tArgs ) ) + local nTask = shell.openTab(table.unpack(tArgs)) if nTask then - shell.switchTab( nTask ) + shell.switchTab(nTask) end else - local nTask = shell.openTab( "shell" ) + local nTask = shell.openTab("shell") if nTask then - shell.switchTab( nTask ) + shell.switchTab(nTask) end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua b/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua index 75dd3b3da..c675f2dc6 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua @@ -12,84 +12,84 @@ local bWindowsResized = false local nScrollPos = 1 local bScrollRight = false -local function selectProcess( n ) +local function selectProcess(n) if nCurrentProcess ~= n then if nCurrentProcess then - local tOldProcess = tProcesses[ nCurrentProcess ] - tOldProcess.window.setVisible( false ) + local tOldProcess = tProcesses[nCurrentProcess] + tOldProcess.window.setVisible(false) end nCurrentProcess = n if nCurrentProcess then - local tNewProcess = tProcesses[ nCurrentProcess ] - tNewProcess.window.setVisible( true ) + local tNewProcess = tProcesses[nCurrentProcess] + tNewProcess.window.setVisible(true) tNewProcess.bInteracted = true end end end -local function setProcessTitle( n, sTitle ) - tProcesses[ n ].sTitle = sTitle +local function setProcessTitle(n, sTitle) + tProcesses[n].sTitle = sTitle end -local function resumeProcess( nProcess, sEvent, ... ) - local tProcess = tProcesses[ nProcess ] +local function resumeProcess(nProcess, sEvent, ...) + local tProcess = tProcesses[nProcess] local sFilter = tProcess.sFilter if sFilter == nil or sFilter == sEvent or sEvent == "terminate" then local nPreviousProcess = nRunningProcess nRunningProcess = nProcess - term.redirect( tProcess.terminal ) - local ok, result = coroutine.resume( tProcess.co, sEvent, ... ) + term.redirect(tProcess.terminal) + local ok, result = coroutine.resume(tProcess.co, sEvent, ...) tProcess.terminal = term.current() if ok then tProcess.sFilter = result else - printError( result ) + printError(result) end nRunningProcess = nPreviousProcess end end -local function launchProcess( bFocus, tProgramEnv, sProgramPath, ... ) - local tProgramArgs = table.pack( ... ) +local function launchProcess(bFocus, tProgramEnv, sProgramPath, ...) + local tProgramArgs = table.pack(...) local nProcess = #tProcesses + 1 local tProcess = {} - tProcess.sTitle = fs.getName( sProgramPath ) + tProcess.sTitle = fs.getName(sProgramPath) if bShowMenu then - tProcess.window = window.create( parentTerm, 1, 2, w, h - 1, false ) + tProcess.window = window.create(parentTerm, 1, 2, w, h - 1, false) else - tProcess.window = window.create( parentTerm, 1, 1, w, h, false ) + tProcess.window = window.create(parentTerm, 1, 1, w, h, false) end - tProcess.co = coroutine.create( function() - os.run( tProgramEnv, sProgramPath, table.unpack( tProgramArgs, 1, tProgramArgs.n ) ) + tProcess.co = coroutine.create(function() + os.run(tProgramEnv, sProgramPath, table.unpack(tProgramArgs, 1, tProgramArgs.n)) if not tProcess.bInteracted then - term.setCursorBlink( false ) - print( "Press any key to continue" ) - os.pullEvent( "char" ) + term.setCursorBlink(false) + print("Press any key to continue") + os.pullEvent("char") end - end ) + end) tProcess.sFilter = nil tProcess.terminal = tProcess.window tProcess.bInteracted = false - tProcesses[ nProcess ] = tProcess + tProcesses[nProcess] = tProcess if bFocus then - selectProcess( nProcess ) + selectProcess(nProcess) end - resumeProcess( nProcess ) + resumeProcess(nProcess) return nProcess end -local function cullProcess( nProcess ) - local tProcess = tProcesses[ nProcess ] - if coroutine.status( tProcess.co ) == "dead" then +local function cullProcess(nProcess) + local tProcess = tProcesses[nProcess] + if coroutine.status(tProcess.co) == "dead" then if nCurrentProcess == nProcess then - selectProcess( nil ) + selectProcess(nil) end - table.remove( tProcesses, nProcess ) + table.remove(tProcesses, nProcess) if nCurrentProcess == nil then if nProcess > 1 then - selectProcess( nProcess - 1 ) + selectProcess(nProcess - 1) elseif #tProcesses > 0 then - selectProcess( 1 ) + selectProcess(1) end end if nScrollPos ~= 1 then @@ -103,7 +103,7 @@ end local function cullProcesses() local culled = false for n = #tProcesses, 1, -1 do - culled = culled or cullProcess( n ) + culled = culled or cullProcess(n) end return culled end @@ -121,40 +121,40 @@ end local function redrawMenu() if bShowMenu then -- Draw menu - parentTerm.setCursorPos( 1, 1 ) - parentTerm.setBackgroundColor( menuOtherBgColor ) + parentTerm.setCursorPos(1, 1) + parentTerm.setBackgroundColor(menuOtherBgColor) parentTerm.clearLine() local nCharCount = 0 local nSize = parentTerm.getSize() if nScrollPos ~= 1 then - parentTerm.setTextColor( menuOtherTextColor ) - parentTerm.setBackgroundColor( menuOtherBgColor ) - parentTerm.write( "<" ) + parentTerm.setTextColor(menuOtherTextColor) + parentTerm.setBackgroundColor(menuOtherBgColor) + parentTerm.write("<") nCharCount = 1 end for n = nScrollPos, #tProcesses do if n == nCurrentProcess then - parentTerm.setTextColor( menuMainTextColor ) - parentTerm.setBackgroundColor( menuMainBgColor ) + parentTerm.setTextColor(menuMainTextColor) + parentTerm.setBackgroundColor(menuMainBgColor) else - parentTerm.setTextColor( menuOtherTextColor ) - parentTerm.setBackgroundColor( menuOtherBgColor ) + parentTerm.setTextColor(menuOtherTextColor) + parentTerm.setBackgroundColor(menuOtherBgColor) end - parentTerm.write( " " .. tProcesses[n].sTitle .. " " ) + parentTerm.write(" " .. tProcesses[n].sTitle .. " ") nCharCount = nCharCount + #tProcesses[n].sTitle + 2 end if nCharCount > nSize then - parentTerm.setTextColor( menuOtherTextColor ) - parentTerm.setBackgroundColor( menuOtherBgColor ) - parentTerm.setCursorPos( nSize, 1 ) - parentTerm.write( ">" ) + parentTerm.setTextColor(menuOtherTextColor) + parentTerm.setBackgroundColor(menuOtherBgColor) + parentTerm.setCursorPos(nSize, 1) + parentTerm.write(">") bScrollRight = true else bScrollRight = false end -- Put the cursor back where it should be - local tProcess = tProcesses[ nCurrentProcess ] + local tProcess = tProcesses[nCurrentProcess] if tProcess then tProcess.window.restoreCursor() end @@ -174,15 +174,15 @@ local function resizeWindows() local tProcess = tProcesses[n] local x, y = tProcess.window.getCursorPos() if y > windowHeight then - tProcess.window.scroll( y - windowHeight ) - tProcess.window.setCursorPos( x, windowHeight ) + tProcess.window.scroll(y - windowHeight) + tProcess.window.setCursorPos(x, windowHeight) end - tProcess.window.reposition( 1, windowY, w, windowHeight ) + tProcess.window.reposition(1, windowY, w, windowHeight) end bWindowsResized = true end -local function setMenuVisible( bVis ) +local function setMenuVisible(bVis) if bShowMenu ~= bVis then bShowMenu = bVis resizeWindows() @@ -196,17 +196,17 @@ function multishell.getFocus() return nCurrentProcess end -function multishell.setFocus( n ) +function multishell.setFocus(n) expect(1, n, "number") if n >= 1 and n <= #tProcesses then - selectProcess( n ) + selectProcess(n) redrawMenu() return true end return false end -function multishell.getTitle( n ) +function multishell.getTitle(n) expect(1, n, "number") if n >= 1 and n <= #tProcesses then return tProcesses[n].sTitle @@ -214,11 +214,11 @@ function multishell.getTitle( n ) return nil end -function multishell.setTitle( n, sTitle ) +function multishell.setTitle(n, sTitle) expect(1, n, "number") expect(2, sTitle, "string") if n >= 1 and n <= #tProcesses then - setProcessTitle( n, sTitle ) + setProcessTitle(n, sTitle) redrawMenu() end end @@ -227,14 +227,14 @@ function multishell.getCurrent() return nRunningProcess end -function multishell.launch( tProgramEnv, sProgramPath, ... ) +function multishell.launch(tProgramEnv, sProgramPath, ...) expect(1, tProgramEnv, "table") expect(2, sProgramPath, "string") local previousTerm = term.current() - setMenuVisible( #tProcesses + 1 >= 2 ) - local nResult = launchProcess( false, tProgramEnv, sProgramPath, ... ) + setMenuVisible(#tProcesses + 1 >= 2) + local nResult = launchProcess(false, tProgramEnv, sProgramPath, ...) redrawMenu() - term.redirect( previousTerm ) + term.redirect(previousTerm) return nResult end @@ -244,16 +244,16 @@ end -- Begin parentTerm.clear() -setMenuVisible( false ) -launchProcess( true, { +setMenuVisible(false) +launchProcess(true, { ["shell"] = shell, ["multishell"] = multishell, -}, "/rom/programs/shell.lua" ) +}, "/rom/programs/shell.lua") -- Run processes while #tProcesses > 0 do -- Get the event - local tEventData = table.pack( os.pullEventRaw() ) + local tEventData = table.pack(os.pullEventRaw()) local sEvent = tEventData[1] if sEvent == "term_resize" then -- Resize event @@ -264,9 +264,9 @@ while #tProcesses > 0 do elseif sEvent == "char" or sEvent == "key" or sEvent == "key_up" or sEvent == "paste" or sEvent == "terminate" then -- Keyboard event -- Passthrough to current process - resumeProcess( nCurrentProcess, table.unpack( tEventData, 1, tEventData.n ) ) - if cullProcess( nCurrentProcess ) then - setMenuVisible( #tProcesses >= 2 ) + resumeProcess(nCurrentProcess, table.unpack(tEventData, 1, tEventData.n)) + if cullProcess(nCurrentProcess) then + setMenuVisible(#tProcesses >= 2) redrawMenu() end @@ -289,7 +289,7 @@ while #tProcesses > 0 do for n = nScrollPos, #tProcesses do local tabEnd = tabStart + #tProcesses[n].sTitle + 1 if x >= tabStart and x <= tabEnd then - selectProcess( n ) + selectProcess(n) redrawMenu() break end @@ -298,9 +298,9 @@ while #tProcesses > 0 do end else -- Passthrough to current process - resumeProcess( nCurrentProcess, sEvent, button, x, bShowMenu and y - 1 or y ) - if cullProcess( nCurrentProcess ) then - setMenuVisible( #tProcesses >= 2 ) + resumeProcess(nCurrentProcess, sEvent, button, x, bShowMenu and y - 1 or y) + if cullProcess(nCurrentProcess) then + setMenuVisible(#tProcesses >= 2) redrawMenu() end end @@ -318,9 +318,9 @@ while #tProcesses > 0 do end elseif not (bShowMenu and y == 1) then -- Passthrough to current process - resumeProcess( nCurrentProcess, sEvent, p1, x, bShowMenu and y - 1 or y ) - if cullProcess( nCurrentProcess ) then - setMenuVisible( #tProcesses >= 2 ) + resumeProcess(nCurrentProcess, sEvent, p1, x, bShowMenu and y - 1 or y) + if cullProcess(nCurrentProcess) then + setMenuVisible(#tProcesses >= 2) redrawMenu() end end @@ -330,10 +330,10 @@ while #tProcesses > 0 do -- Passthrough to all processes local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event for n = 1, nLimit do - resumeProcess( n, table.unpack( tEventData, 1, tEventData.n ) ) + resumeProcess(n, table.unpack(tEventData, 1, tEventData.n)) end if cullProcesses() then - setMenuVisible( #tProcesses >= 2 ) + setMenuVisible(#tProcesses >= 2) redrawMenu() end end @@ -342,15 +342,15 @@ while #tProcesses > 0 do -- Pass term_resize to all processes local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event for n = 1, nLimit do - resumeProcess( n, "term_resize" ) + resumeProcess(n, "term_resize") end bWindowsResized = false if cullProcesses() then - setMenuVisible( #tProcesses >= 2 ) + setMenuVisible(#tProcesses >= 2) redrawMenu() end end end -- Shutdown -term.redirect( parentTerm ) +term.redirect(parentTerm) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/alias.lua b/src/main/resources/data/computercraft/lua/rom/programs/alias.lua index c4f8c5ffe..d35eb7707 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/alias.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/alias.lua @@ -1,7 +1,7 @@ local tArgs = { ... } if #tArgs > 2 then - print( "Usage: alias " ) + print("Usage: alias ") return end @@ -10,17 +10,17 @@ local sProgram = tArgs[2] if sAlias and sProgram then -- Set alias - shell.setAlias( sAlias, sProgram ) + shell.setAlias(sAlias, sProgram) elseif sAlias then -- Clear alias - shell.clearAlias( sAlias ) + shell.clearAlias(sAlias) else -- List aliases local tAliases = shell.aliases() local tList = {} - for sAlias, sCommand in pairs( tAliases ) do - table.insert( tList, sAlias .. ":" .. sCommand ) + for sAlias, sCommand in pairs(tAliases) do + table.insert(tList, sAlias .. ":" .. sCommand) end - table.sort( tList ) - textutils.pagedTabulate( tList ) + table.sort(tList) + textutils.pagedTabulate(tList) end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/apis.lua b/src/main/resources/data/computercraft/lua/rom/programs/apis.lua index 7ef16e96f..801477650 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/apis.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/apis.lua @@ -1,15 +1,15 @@ local tApis = {} -for k, v in pairs( _G ) do +for k, v in pairs(_G) do if type(k) == "string" and type(v) == "table" and k ~= "_G" then - table.insert( tApis, k ) + table.insert(tApis, k) end end -table.insert( tApis, "shell" ) -table.insert( tApis, "package" ) +table.insert(tApis, "shell") +table.insert(tApis, "package") if multishell then - table.insert( tApis, "multishell" ) + table.insert(tApis, "multishell") end -table.sort( tApis ) +table.sort(tApis) -textutils.pagedTabulate( tApis ) +textutils.pagedTabulate(tApis) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/cd.lua b/src/main/resources/data/computercraft/lua/rom/programs/cd.lua index abadf5366..6f05a98ac 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/cd.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/cd.lua @@ -1,14 +1,14 @@ local tArgs = { ... } if #tArgs < 1 then - print( "Usage: cd " ) + print("Usage: cd ") return end -local sNewDir = shell.resolve( tArgs[1] ) -if fs.isDir( sNewDir ) then - shell.setDir( sNewDir ) +local sNewDir = shell.resolve(tArgs[1]) +if fs.isDir(sNewDir) then + shell.setDir(sNewDir) else - print( "Not a directory" ) + print("Not a directory") return end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/clear.lua b/src/main/resources/data/computercraft/lua/rom/programs/clear.lua index 50283c8d7..d69a29993 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/clear.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/clear.lua @@ -1,2 +1,2 @@ term.clear() -term.setCursorPos( 1, 1 ) +term.setCursorPos(1, 1) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/command/commands.lua b/src/main/resources/data/computercraft/lua/rom/programs/command/commands.lua index 230d766f7..dacc5626d 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/command/commands.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/command/commands.lua @@ -1,16 +1,16 @@ if not commands then - printError( "Requires a Command Computer." ) + printError("Requires a Command Computer.") return end local tCommands = commands.list() -table.sort( tCommands ) +table.sort(tCommands) if term.isColor() then - term.setTextColor( colors.green ) + term.setTextColor(colors.green) end -print( "Available commands:" ) -term.setTextColor( colors.white ) +print("Available commands:") +term.setTextColor(colors.white) -textutils.pagedTabulate( tCommands ) +textutils.pagedTabulate(tCommands) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/command/exec.lua b/src/main/resources/data/computercraft/lua/rom/programs/command/exec.lua index c54b3f567..b50c8ec20 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/command/exec.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/command/exec.lua @@ -1,40 +1,40 @@ local tArgs = { ... } if not commands then - printError( "Requires a Command Computer." ) + printError("Requires a Command Computer.") return end if #tArgs == 0 then - printError( "Usage: exec " ) + printError("Usage: exec ") return end -local function printSuccess( text ) +local function printSuccess(text) if term.isColor() then - term.setTextColor( colors.green ) + term.setTextColor(colors.green) end - print( text ) - term.setTextColor( colors.white ) + print(text) + term.setTextColor(colors.white) end -local sCommand = string.lower( tArgs[1] ) +local sCommand = string.lower(tArgs[1]) for n = 2, #tArgs do sCommand = sCommand .. " " .. tArgs[n] end -local bResult, tOutput = commands.exec( sCommand ) +local bResult, tOutput = commands.exec(sCommand) if bResult then - printSuccess( "Success" ) + printSuccess("Success") if #tOutput > 0 then for n = 1, #tOutput do - print( tOutput[n] ) + print(tOutput[n]) end end else - printError( "Failed" ) + printError("Failed") if #tOutput > 0 then for n = 1, #tOutput do - print( tOutput[n] ) + print(tOutput[n]) end end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/copy.lua b/src/main/resources/data/computercraft/lua/rom/programs/copy.lua index c8d66459b..d50132f82 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/copy.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/copy.lua @@ -1,32 +1,32 @@ local tArgs = { ... } if #tArgs < 2 then - print( "Usage: cp " ) + print("Usage: cp ") return end -local sSource = shell.resolve( tArgs[1] ) -local sDest = shell.resolve( tArgs[2] ) -local tFiles = fs.find( sSource ) +local sSource = shell.resolve(tArgs[1]) +local sDest = shell.resolve(tArgs[2]) +local tFiles = fs.find(sSource) if #tFiles > 0 then - for _, sFile in ipairs( tFiles ) do - if fs.isDir( sDest ) then - fs.copy( sFile, fs.combine( sDest, fs.getName(sFile) ) ) + for _, sFile in ipairs(tFiles) do + if fs.isDir(sDest) then + fs.copy(sFile, fs.combine(sDest, fs.getName(sFile))) elseif #tFiles == 1 then - if fs.exists( sDest ) then - printError( "Destination exists" ) - elseif fs.isReadOnly( sDest ) then - printError( "Destination is read-only" ) - elseif fs.getFreeSpace( sDest ) < fs.getSize( sFile ) then - printError( "Not enough space" ) + if fs.exists(sDest) then + printError("Destination exists") + elseif fs.isReadOnly(sDest) then + printError("Destination is read-only") + elseif fs.getFreeSpace(sDest) < fs.getSize(sFile) then + printError("Not enough space") else - fs.copy( sFile, sDest ) + fs.copy(sFile, sDest) end else - printError( "Cannot overwrite file multiple times" ) + printError("Cannot overwrite file multiple times") return end end else - printError( "No matching files" ) + printError("No matching files") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/drive.lua b/src/main/resources/data/computercraft/lua/rom/programs/drive.lua index 807cf88b4..799b65ecc 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/drive.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/drive.lua @@ -3,19 +3,19 @@ local tArgs = { ... } -- Get where a directory is mounted local sPath = shell.dir() if tArgs[1] ~= nil then - sPath = shell.resolve( tArgs[1] ) + sPath = shell.resolve(tArgs[1]) end -if fs.exists( sPath ) then - write( fs.getDrive( sPath ) .. " (" ) - local nSpace = fs.getFreeSpace( sPath ) +if fs.exists(sPath) then + write(fs.getDrive(sPath) .. " (") + local nSpace = fs.getFreeSpace(sPath) if nSpace >= 1000 * 1000 then - print( math.floor( nSpace / (100 * 1000) ) / 10 .. "MB remaining)" ) + print(math.floor(nSpace / (100 * 1000)) / 10 .. "MB remaining)") elseif nSpace >= 1000 then - print( math.floor( nSpace / 100 ) / 10 .. "KB remaining)" ) + print(math.floor(nSpace / 100) / 10 .. "KB remaining)") else - print( nSpace .. "B remaining)" ) + print(nSpace .. "B remaining)") end else - print( "No such path" ) + print("No such path") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua index 5e6cfee1c..a6ea4d8d0 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua @@ -1,22 +1,22 @@ -- Get file to edit local tArgs = { ... } if #tArgs == 0 then - print( "Usage: edit " ) + print("Usage: edit ") return end -- Error checking -local sPath = shell.resolve( tArgs[1] ) -local bReadOnly = fs.isReadOnly( sPath ) -if fs.exists( sPath ) and fs.isDir( sPath ) then - print( "Cannot edit a directory." ) +local sPath = shell.resolve(tArgs[1]) +local bReadOnly = fs.isReadOnly(sPath) +if fs.exists(sPath) and fs.isDir(sPath) then + print("Cannot edit a directory.") return end -- Create .lua files by default -if not fs.exists( sPath ) and not string.find( sPath, "%." ) then - local sExtension = settings.get("edit.default_extension", "" ) - if sExtension ~= "" and type( sExtension ) == "string" then +if not fs.exists(sPath) and not string.find(sPath, "%.") then + local sExtension = settings.get("edit.default_extension", "") + if sExtension ~= "" and type(sExtension) == "string" then sPath = sPath .. "." .. sExtension end end @@ -51,59 +51,59 @@ local bMenu = false local nMenuItem = 1 local tMenuItems = {} if not bReadOnly then - table.insert( tMenuItems, "Save" ) + table.insert(tMenuItems, "Save") end if shell.openTab then - table.insert( tMenuItems, "Run" ) + table.insert(tMenuItems, "Run") end -if peripheral.find( "printer" ) then - table.insert( tMenuItems, "Print" ) +if peripheral.find("printer") then + table.insert(tMenuItems, "Print") end -table.insert( tMenuItems, "Exit" ) +table.insert(tMenuItems, "Exit") local sStatus = "Press Ctrl to access menu" if #sStatus > w - 5 then sStatus = "Press Ctrl for menu" end -local function load( _sPath ) +local function load(_sPath) tLines = {} - if fs.exists( _sPath ) then - local file = io.open( _sPath, "r" ) + if fs.exists(_sPath) then + local file = io.open(_sPath, "r") local sLine = file:read() while sLine do - table.insert( tLines, sLine ) + table.insert(tLines, sLine) sLine = file:read() end file:close() end if #tLines == 0 then - table.insert( tLines, "" ) + table.insert(tLines, "") end end -local function save( _sPath ) +local function save(_sPath) -- Create intervening folder - local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() ) - if not fs.exists( sDir ) then - fs.makeDir( sDir ) + local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len()) + if not fs.exists(sDir) then + fs.makeDir(sDir) end -- Save local file, fileerr local function innerSave() - file, fileerr = fs.open( _sPath, "w" ) + file, fileerr = fs.open(_sPath, "w") if file then - for _, sLine in ipairs( tLines ) do - file.write( sLine .. "\n" ) + for _, sLine in ipairs(tLines) do + file.write(sLine .. "\n") end else - error( "Failed to open " .. _sPath ) + error("Failed to open " .. _sPath) end end - local ok, err = pcall( innerSave ) + local ok, err = pcall(innerSave) if file then file.close() end @@ -134,38 +134,38 @@ local tKeywords = { ["while"] = true, } -local function tryWrite( sLine, regex, colour ) - local match = string.match( sLine, regex ) +local function tryWrite(sLine, regex, colour) + local match = string.match(sLine, regex) if match then if type(colour) == "number" then - term.setTextColour( colour ) + term.setTextColour(colour) else - term.setTextColour( colour(match) ) + term.setTextColour(colour(match)) end - term.write( match ) - term.setTextColour( textColour ) - return string.sub( sLine, #match + 1 ) + term.write(match) + term.setTextColour(textColour) + return string.sub(sLine, #match + 1) end return nil end -local function writeHighlighted( sLine ) +local function writeHighlighted(sLine) while #sLine > 0 do sLine = - tryWrite( sLine, "^%-%-%[%[.-%]%]", commentColour ) or - tryWrite( sLine, "^%-%-.*", commentColour ) or - tryWrite( sLine, "^\"\"", stringColour ) or - tryWrite( sLine, "^\".-[^\\]\"", stringColour ) or - tryWrite( sLine, "^\'\'", stringColour ) or - tryWrite( sLine, "^\'.-[^\\]\'", stringColour ) or - tryWrite( sLine, "^%[%[.-%]%]", stringColour ) or - tryWrite( sLine, "^[%w_]+", function( match ) - if tKeywords[ match ] then + tryWrite(sLine, "^%-%-%[%[.-%]%]", commentColour) or + tryWrite(sLine, "^%-%-.*", commentColour) or + tryWrite(sLine, "^\"\"", stringColour) or + tryWrite(sLine, "^\".-[^\\]\"", stringColour) or + tryWrite(sLine, "^\'\'", stringColour) or + tryWrite(sLine, "^\'.-[^\\]\'", stringColour) or + tryWrite(sLine, "^%[%[.-%]%]", stringColour) or + tryWrite(sLine, "^[%w_]+", function(match) + if tKeywords[match] then return keywordColour end return textColour - end ) or - tryWrite( sLine, "^[^%w_]", textColour ) + end) or + tryWrite(sLine, "^[^%w_]", textColour) end end @@ -173,14 +173,14 @@ local tCompletions local nCompletion local tCompleteEnv = _ENV -local function complete( sLine ) - if settings.get( "edit.autocomplete" ) then - local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.:]+$" ) +local function complete(sLine) + if settings.get("edit.autocomplete") then + local nStartPos = string.find(sLine, "[a-zA-Z0-9_%.:]+$") if nStartPos then - sLine = string.sub( sLine, nStartPos ) + sLine = string.sub(sLine, nStartPos) end if #sLine > 0 then - return textutils.complete( sLine, tCompleteEnv ) + return textutils.complete(sLine, tCompleteEnv) end end return nil @@ -189,7 +189,7 @@ end local function recomplete() local sLine = tLines[y] if not bMenu and not bReadOnly and x == #sLine + 1 then - tCompletions = complete( sLine ) + tCompletions = complete(sLine) if tCompletions and #tCompletions > 0 then nCompletion = 1 else @@ -201,85 +201,85 @@ local function recomplete() end end -local function writeCompletion( sLine ) +local function writeCompletion(sLine) if nCompletion then - local sCompletion = tCompletions[ nCompletion ] - term.setTextColor( colours.white ) - term.setBackgroundColor( colours.grey ) - term.write( sCompletion ) - term.setTextColor( textColour ) - term.setBackgroundColor( bgColour ) + local sCompletion = tCompletions[nCompletion] + term.setTextColor(colours.white) + term.setBackgroundColor(colours.grey) + term.write(sCompletion) + term.setTextColor(textColour) + term.setBackgroundColor(bgColour) end end local function redrawText() local cursorX, cursorY = x, y for y = 1, h - 1 do - term.setCursorPos( 1 - scrollX, y ) + term.setCursorPos(1 - scrollX, y) term.clearLine() - local sLine = tLines[ y + scrollY ] + local sLine = tLines[y + scrollY] if sLine ~= nil then - writeHighlighted( sLine ) + writeHighlighted(sLine) if cursorY == y and cursorX == #sLine + 1 then writeCompletion() end end end - term.setCursorPos( x - scrollX, y - scrollY ) + term.setCursorPos(x - scrollX, y - scrollY) end local function redrawLine(_nY) local sLine = tLines[_nY] if sLine then - term.setCursorPos( 1 - scrollX, _nY - scrollY ) + term.setCursorPos(1 - scrollX, _nY - scrollY) term.clearLine() - writeHighlighted( sLine ) + writeHighlighted(sLine) if _nY == y and x == #sLine + 1 then writeCompletion() end - term.setCursorPos( x - scrollX, _nY - scrollY ) + term.setCursorPos(x - scrollX, _nY - scrollY) end end local function redrawMenu() -- Clear line - term.setCursorPos( 1, h ) + term.setCursorPos(1, h) term.clearLine() -- Draw line numbers - term.setCursorPos( w - #( "Ln " .. y ) + 1, h ) - term.setTextColour( highlightColour ) - term.write( "Ln " ) - term.setTextColour( textColour ) - term.write( y ) + term.setCursorPos(w - #("Ln " .. y) + 1, h) + term.setTextColour(highlightColour) + term.write("Ln ") + term.setTextColour(textColour) + term.write(y) - term.setCursorPos( 1, h ) + term.setCursorPos(1, h) if bMenu then -- Draw menu - term.setTextColour( textColour ) - for nItem, sItem in pairs( tMenuItems ) do + term.setTextColour(textColour) + for nItem, sItem in pairs(tMenuItems) do if nItem == nMenuItem then - term.setTextColour( highlightColour ) - term.write( "[" ) - term.setTextColour( textColour ) - term.write( sItem ) - term.setTextColour( highlightColour ) - term.write( "]" ) - term.setTextColour( textColour ) + term.setTextColour(highlightColour) + term.write("[") + term.setTextColour(textColour) + term.write(sItem) + term.setTextColour(highlightColour) + term.write("]") + term.setTextColour(textColour) else - term.write( " " .. sItem .. " " ) + term.write(" " .. sItem .. " ") end end else -- Draw status - term.setTextColour( highlightColour ) - term.write( sStatus ) - term.setTextColour( textColour ) + term.setTextColour(highlightColour) + term.write(sStatus) + term.setTextColour(textColour) end -- Reset cursor - term.setCursorPos( x - scrollX, y - scrollY ) + term.setCursorPos(x - scrollX, y - scrollY) end local tMenuFuncs = { @@ -287,7 +287,7 @@ local tMenuFuncs = { if bReadOnly then sStatus = "Access denied" else - local ok, _, fileerr = save( sPath ) + local ok, _, fileerr = save(sPath) if ok then sStatus = "Saved to " .. sPath else @@ -301,14 +301,14 @@ local tMenuFuncs = { redrawMenu() end, Print = function() - local printer = peripheral.find( "printer" ) + local printer = peripheral.find("printer") if not printer then sStatus = "No printer attached" return end local nPage = 0 - local sName = fs.getName( sPath ) + local sName = fs.getName(sPath) if printer.getInkLevel() < 1 then sStatus = "Printer out of ink" return @@ -326,7 +326,7 @@ local tMenuFuncs = { } printerTerminal.scroll = function() if nPage == 1 then - printer.setPageTitle( sName .. " (page " .. nPage .. ")" ) + printer.setPageTitle(sName .. " (page " .. nPage .. ")") end while not printer.newPage() do @@ -338,38 +338,38 @@ local tMenuFuncs = { sStatus = "Printer output tray full, please empty" end - term.redirect( screenTerminal ) + term.redirect(screenTerminal) redrawMenu() - term.redirect( printerTerminal ) + term.redirect(printerTerminal) sleep(0.5) end nPage = nPage + 1 if nPage == 1 then - printer.setPageTitle( sName ) + printer.setPageTitle(sName) else - printer.setPageTitle( sName .. " (page " .. nPage .. ")" ) + printer.setPageTitle(sName .. " (page " .. nPage .. ")") end end bMenu = false - term.redirect( printerTerminal ) - local ok, error = pcall( function() + term.redirect(printerTerminal) + local ok, error = pcall(function() term.scroll() - for _, sLine in ipairs( tLines ) do - print( sLine ) + for _, sLine in ipairs(tLines) do + print(sLine) end - end ) - term.redirect( screenTerminal ) + end) + term.redirect(screenTerminal) if not ok then - print( error ) + print(error) end while not printer.endPage() do sStatus = "Printer output tray full, please empty" redrawMenu() - sleep( 0.5 ) + sleep(0.5) end bMenu = true @@ -385,15 +385,15 @@ local tMenuFuncs = { end, Run = function() local sTempPath = "/.temp" - local ok = save( sTempPath ) + local ok = save(sTempPath) if ok then - local nTask = shell.openTab( sTempPath ) + local nTask = shell.openTab(sTempPath) if nTask then - shell.switchTab( nTask ) + shell.switchTab(nTask) else sStatus = "Error starting Task" end - fs.delete( sTempPath ) + fs.delete(sTempPath) else sStatus = "Error saving to " .. sTempPath end @@ -401,16 +401,16 @@ local tMenuFuncs = { end, } -local function doMenuItem( _n ) +local function doMenuItem(_n) tMenuFuncs[tMenuItems[_n]]() if bMenu then bMenu = false - term.setCursorBlink( true ) + term.setCursorBlink(true) end redrawMenu() end -local function setCursor( newX, newY ) +local function setCursor(newX, newY) local _, oldY = x, y x, y = newX, newY local screenX = x - scrollX @@ -441,12 +441,12 @@ local function setCursor( newX, newY ) if bRedraw then redrawText() elseif y ~= oldY then - redrawLine( oldY ) - redrawLine( y ) + redrawLine(oldY) + redrawLine(y) else - redrawLine( y ) + redrawLine(y) end - term.setCursorPos( screenX, screenY ) + term.setCursorPos(screenX, screenY) redrawMenu() end @@ -454,10 +454,10 @@ end -- Actual program functionality begins load(sPath) -term.setBackgroundColour( bgColour ) +term.setBackgroundColour(bgColour) term.clear() term.setCursorPos(x, y) -term.setCursorBlink( true ) +term.setCursorBlink(true) recomplete() redrawText() @@ -466,9 +466,9 @@ redrawMenu() local function acceptCompletion() if nCompletion then -- Append the completion - local sCompletion = tCompletions[ nCompletion ] + local sCompletion = tCompletions[nCompletion] tLines[y] = tLines[y] .. sCompletion - setCursor( x + #sCompletion , y ) + setCursor(x + #sCompletion , y) end end @@ -490,7 +490,7 @@ while bRunning do elseif y > 1 then -- Move cursor up setCursor( - math.min( x, #tLines[y - 1] + 1 ), + math.min(x, #tLines[y - 1] + 1), y - 1 ) end @@ -511,7 +511,7 @@ while bRunning do elseif y < #tLines then -- Move cursor down setCursor( - math.min( x, #tLines[y + 1] + 1 ), + math.min(x, #tLines[y + 1] + 1), y + 1 ) end @@ -527,7 +527,7 @@ while bRunning do -- Indent line local sLine = tLines[y] tLines[y] = string.sub(sLine, 1, x - 1) .. " " .. string.sub(sLine, x) - setCursor( x + 4, y ) + setCursor(x + 4, y) end end @@ -542,7 +542,7 @@ while bRunning do newY = 1 end setCursor( - math.min( x, #tLines[newY] + 1 ), + math.min(x, #tLines[newY] + 1), newY ) end @@ -557,8 +557,8 @@ while bRunning do else newY = #tLines end - local newX = math.min( x, #tLines[newY] + 1 ) - setCursor( newX, newY ) + local newX = math.min(x, #tLines[newY] + 1) + setCursor(newX, newY) end elseif param == keys.home then @@ -576,7 +576,7 @@ while bRunning do -- Move cursor to the end local nLimit = #tLines[y] + 1 if x < nLimit then - setCursor( nLimit, y ) + setCursor(nLimit, y) end end @@ -585,9 +585,9 @@ while bRunning do if not bMenu then if x > 1 then -- Move cursor left - setCursor( x - 1, y ) + setCursor(x - 1, y) elseif x == 1 and y > 1 then - setCursor( #tLines[y - 1] + 1, y - 1 ) + setCursor(#tLines[y - 1] + 1, y - 1) end else -- Move menu left @@ -604,13 +604,13 @@ while bRunning do local nLimit = #tLines[y] + 1 if x < nLimit then -- Move cursor right - setCursor( x + 1, y ) + setCursor(x + 1, y) elseif nCompletion and x == #tLines[y] + 1 then -- Accept autocomplete acceptCompletion() elseif x == nLimit and y < #tLines then -- Go to next line - setCursor( 1, y + 1 ) + setCursor(1, y + 1) end else -- Move menu right @@ -632,7 +632,7 @@ while bRunning do redrawLine(y) elseif y < #tLines then tLines[y] = tLines[y] .. tLines[y + 1] - table.remove( tLines, y + 1 ) + table.remove(tLines, y + 1) recomplete() redrawText() end @@ -646,17 +646,17 @@ while bRunning do local sLine = tLines[y] if x > 4 and string.sub(sLine, x - 4, x - 1) == " " and not string.sub(sLine, 1, x - 1):find("%S") then tLines[y] = string.sub(sLine, 1, x - 5) .. string.sub(sLine, x) - setCursor( x - 4, y ) + setCursor(x - 4, y) else tLines[y] = string.sub(sLine, 1, x - 2) .. string.sub(sLine, x) - setCursor( x - 1, y ) + setCursor(x - 1, y) end elseif y > 1 then -- Remove newline local sPrevLen = #tLines[y - 1] tLines[y - 1] = tLines[y - 1] .. tLines[y] - table.remove( tLines, y ) - setCursor( sPrevLen + 1, y - 1 ) + table.remove(tLines, y) + setCursor(sPrevLen + 1, y - 1) redrawText() end end @@ -671,13 +671,13 @@ while bRunning do spaces = 0 end tLines[y] = string.sub(sLine, 1, x - 1) - table.insert( tLines, y + 1, string.rep(' ', spaces) .. string.sub(sLine, x) ) - setCursor( spaces + 1, y + 1 ) + table.insert(tLines, y + 1, string.rep(' ', spaces) .. string.sub(sLine, x)) + setCursor(spaces + 1, y + 1) redrawText() elseif bMenu then -- Menu selection - doMenuItem( nMenuItem ) + doMenuItem(nMenuItem) end @@ -685,9 +685,9 @@ while bRunning do -- Menu toggle bMenu = not bMenu if bMenu then - term.setCursorBlink( false ) + term.setCursorBlink(false) else - term.setCursorBlink( true ) + term.setCursorBlink(true) end redrawMenu() @@ -698,13 +698,13 @@ while bRunning do -- Input text local sLine = tLines[y] tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x) - setCursor( x + 1, y ) + setCursor(x + 1, y) elseif bMenu then -- Select menu items - for n, sMenuItem in ipairs( tMenuItems ) do + for n, sMenuItem in ipairs(tMenuItems) do if string.lower(string.sub(sMenuItem, 1, 1)) == string.lower(param) then - doMenuItem( n ) + doMenuItem(n) break end end @@ -715,13 +715,13 @@ while bRunning do -- Close menu if open if bMenu then bMenu = false - term.setCursorBlink( true ) + term.setCursorBlink(true) redrawMenu() end -- Input text local sLine = tLines[y] tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x) - setCursor( x + #param , y ) + setCursor(x + #param , y) end elseif sEvent == "mouse_click" then @@ -730,9 +730,9 @@ while bRunning do -- Left click local cx, cy = param2, param3 if cy < h then - local newY = math.min( math.max( scrollY + cy, 1 ), #tLines ) - local newX = math.min( math.max( scrollX + cx, 1 ), #tLines[newY] + 1 ) - setCursor( newX, newY ) + local newY = math.min(math.max(scrollY + cy, 1), #tLines) + local newX = math.min(math.max(scrollX + cx, 1), #tLines[newY] + 1) + setCursor(newX, newY) end end end @@ -761,7 +761,7 @@ while bRunning do elseif sEvent == "term_resize" then w, h = term.getSize() - setCursor( x, y ) + setCursor(x, y) redrawMenu() redrawText() @@ -770,5 +770,5 @@ end -- Cleanup term.clear() -term.setCursorBlink( false ) -term.setCursorPos( 1, 1 ) +term.setCursorBlink(false) +term.setCursorPos(1, 1) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/eject.lua b/src/main/resources/data/computercraft/lua/rom/programs/eject.lua index ad47bbd99..635c2f4e8 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/eject.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/eject.lua @@ -2,17 +2,17 @@ -- Get arguments local tArgs = { ... } if #tArgs == 0 then - print( "Usage: eject " ) + print("Usage: eject ") return end local sDrive = tArgs[1] -- Check the disk exists -local bPresent = disk.isPresent( sDrive ) +local bPresent = disk.isPresent(sDrive) if not bPresent then - print( "Nothing in " .. sDrive .. " drive" ) + print("Nothing in " .. sDrive .. " drive") return end -disk.eject( sDrive ) +disk.eject(sDrive) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua index 758e82074..fbe228091 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -32,7 +32,7 @@ if not term.isColour() then end -- Determines if the file exists, and can be edited on this computer -local tArgs = {...} +local tArgs = { ... } if #tArgs == 0 then print("Usage: paint ") return @@ -45,9 +45,9 @@ if fs.exists(sPath) and fs.isDir(sPath) then end -- Create .nfp files by default -if not fs.exists( sPath ) and not string.find( sPath, "%." ) then - local sExtension = settings.get("paint.default_extension", "" ) - if sExtension ~= "" and type( sExtension ) == "string" then +if not fs.exists(sPath) and not string.find(sPath, "%.") then + local sExtension = settings.get("paint.default_extension", "") + if sExtension ~= "" and type(sExtension) == "string" then sPath = sPath .. "." .. sExtension end end @@ -57,7 +57,7 @@ end -- Functions -- --------------- -local function getCanvasPixel( x, y ) +local function getCanvasPixel(x, y) if canvas[y] then return canvas[y][x] end @@ -69,12 +69,12 @@ end params: colour = the number to convert to a hex value returns: a string representing the chosen colour ]] -local function getCharOf( colour ) +local function getCharOf(colour) -- Incorrect values always convert to nil if type(colour) == "number" then - local value = math.floor( math.log(colour) / math.log(2) ) + 1 + local value = math.floor(math.log(colour) / math.log(2)) + 1 if value >= 1 and value <= 16 then - return string.sub( "0123456789abcdef", value, value ) + return string.sub("0123456789abcdef", value, value) end end return " " @@ -87,9 +87,9 @@ end ]] local tColourLookup = {} for n = 1, 16 do - tColourLookup[ string.byte( "0123456789abcdef", n, n ) ] = 2 ^ (n - 1) + tColourLookup[string.byte("0123456789abcdef", n, n)] = 2 ^ (n - 1) end -local function getColourOf( char ) +local function getColourOf(char) -- Values not in the hex table are transparent (canvas coloured) return tColourLookup[char] end @@ -107,9 +107,9 @@ local function load(path) while sLine do local line = {} for x = 1, w - 2 do - line[x] = getColourOf( string.byte(sLine, x, x) ) + line[x] = getColourOf(string.byte(sLine, x, x)) end - table.insert( canvas, line ) + table.insert(canvas, line) sLine = file.readLine() end file.close() @@ -128,7 +128,7 @@ local function save(path) fs.makeDir(sDir) end - local file, err = fs.open( path, "w" ) + local file, err = fs.open(path, "w") if not file then return false, err end @@ -140,13 +140,13 @@ local function save(path) local sLine = "" local nLastChar = 0 for x = 1, w - 2 do - local c = getCharOf( getCanvasPixel( x, y ) ) + local c = getCharOf(getCanvasPixel(x, y)) sLine = sLine .. c if c ~= " " then nLastChar = x end end - sLine = string.sub( sLine, 1, nLastChar ) + sLine = string.sub(sLine, 1, nLastChar) tLines[y] = sLine if #sLine > 0 then nLastLine = y @@ -155,7 +155,7 @@ local function save(path) -- Save out for n = 1, nLastLine do - file.writeLine( tLines[ n ] ) + file.writeLine(tLines[n]) end file.close() return true @@ -176,38 +176,38 @@ local function drawInterface() -- Colour Picker for i = 1, 16 do term.setCursorPos(w - 1, i) - term.setBackgroundColour( 2 ^ (i - 1) ) + term.setBackgroundColour(2 ^ (i - 1)) term.write(" ") end term.setCursorPos(w - 1, 17) - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) + term.setBackgroundColour(canvasColour) + term.setTextColour(colours.grey) term.write("\127\127") -- Left and Right Selected Colours do term.setCursorPos(w - 1, 18) if leftColour ~= nil then - term.setBackgroundColour( leftColour ) + term.setBackgroundColour(leftColour) term.write(" ") else - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) + term.setBackgroundColour(canvasColour) + term.setTextColour(colours.grey) term.write("\127") end if rightColour ~= nil then - term.setBackgroundColour( rightColour ) + term.setBackgroundColour(rightColour) term.write(" ") else - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) + term.setBackgroundColour(canvasColour) + term.setTextColour(colours.grey) term.write("\127") end end -- Padding - term.setBackgroundColour( canvasColour ) + term.setBackgroundColour(canvasColour) for i = 20, h - 1 do term.setCursorPos(w - 1, i) term.write(" ") @@ -218,15 +218,15 @@ end Converts a single pixel of a single line of the canvas and draws it returns: nil ]] -local function drawCanvasPixel( x, y ) - local pixel = getCanvasPixel( x, y ) +local function drawCanvasPixel(x, y) + local pixel = getCanvasPixel(x, y) if pixel then - term.setBackgroundColour( pixel or canvasColour ) + term.setBackgroundColour(pixel or canvasColour) term.setCursorPos(x, y) term.write(" ") else - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) + term.setBackgroundColour(canvasColour) + term.setTextColour(colours.grey) term.setCursorPos(x, y) term.write("\127") end @@ -236,9 +236,9 @@ end Converts each colour in a single line of the canvas and draws it returns: nil ]] -local function drawCanvasLine( y ) +local function drawCanvasLine(y) for x = 1, w - 2 do - drawCanvasPixel( x, y ) + drawCanvasPixel(x, y) end end @@ -248,7 +248,7 @@ end ]] local function drawCanvas() for y = 1, h - 1 do - drawCanvasLine( y ) + drawCanvasLine(y) end end @@ -377,7 +377,7 @@ local function handleEvents() end canvas[p3][p2] = paintColour - drawCanvasPixel( p2, p3 ) + drawCanvasPixel(p2, p3) end elseif id == "key" then if p1 == keys.leftCtrl or p1 == keys.rightCtrl then diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/redirection.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/redirection.lua index fc6e0f038..7cc1233a6 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/redirection.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/redirection.lua @@ -59,10 +59,10 @@ local cR4 = colors.yellow local tArgs = { ... } --Functions-- -local function printCentred( yc, stg ) +local function printCentred(yc, stg) local xc = math.floor((TermW - #stg) / 2) + 1 term.setCursorPos(xc, yc) - term.write( stg ) + term.write(stg) end local function centerOrgin() @@ -173,9 +173,9 @@ end local function loadLevel(nNum) sLevelTitle = "Level " .. nNum if nNum == nil then return error("nNum == nil") end - local sDir = fs.getDir( shell.getRunningProgram() ) + local sDir = fs.getDir(shell.getRunningProgram()) local sLevelD = sDir .. "/levels/" .. tostring(nNum) .. ".dat" - if not ( fs.exists(sLevelD) or fs.isDir(sLevelD) ) then return error("Level Not Exists : " .. sLevelD) end + if not (fs.exists(sLevelD) or fs.isDir(sLevelD)) then return error("Level Not Exists : " .. sLevelD) end fLevel = fs.open(sLevelD, "r") local wl = true Blocks = tonumber(string.sub(fLevel.readLine(), 1, 1)) @@ -512,20 +512,20 @@ local function gRender(sContext) end function InterFace.drawBar() - term.setBackgroundColor( colors.black ) - term.setTextColor( InterFace.cTitle ) - printCentred( 1, " " .. sLevelTitle .. " " ) + term.setBackgroundColor(colors.black) + term.setTextColor(InterFace.cTitle) + printCentred(1, " " .. sLevelTitle .. " ") term.setCursorPos(1, 1) - term.setBackgroundColor( cW ) - write( " " ) - term.setBackgroundColor( colors.black ) - write( " x " .. tostring(Blocks) .. " " ) + term.setBackgroundColor(cW) + write(" ") + term.setBackgroundColor(colors.black) + write(" x " .. tostring(Blocks) .. " ") - term.setCursorPos( TermW - 8, TermH ) - term.setBackgroundColor( colors.black ) + term.setCursorPos(TermW - 8, TermH) + term.setBackgroundColor(colors.black) term.setTextColour(InterFace.cSpeedD) - write(" <<" ) + write(" <<") if bPaused then term.setTextColour(InterFace.cSpeedA) else @@ -539,9 +539,9 @@ function InterFace.drawBar() end write(" >>") - term.setCursorPos( TermW - 1, 1 ) - term.setBackgroundColor( colors.black ) - term.setTextColour( InterFace.cExit ) + term.setCursorPos(TermW - 1, 1) + term.setBackgroundColor(colors.black) + term.setTextColour(InterFace.cExit) write(" X") term.setBackgroundColor(colors.black) end @@ -612,7 +612,7 @@ local function startG(LevelN) elseif isExit == "retry" then return LevelN elseif fExit == "yes" then - if fs.exists( fs.getDir( shell.getRunningProgram() ) .. "/levels/" .. tostring(LevelN + 1) .. ".dat" ) then + if fs.exists(fs.getDir(shell.getRunningProgram()) .. "/levels/" .. tostring(LevelN + 1) .. ".dat") then return LevelN + 1 else return nil @@ -629,26 +629,26 @@ local ok, err = true, nil --Menu-- local sStartLevel = tArgs[1] if ok and not sStartLevel then - ok, err = pcall( function() + ok, err = pcall(function() term.setTextColor(colors.white) - term.setBackgroundColor( colors.black ) + term.setBackgroundColor(colors.black) term.clear() drawStars() - term.setTextColor( colors.red ) - printCentred( TermH / 2 - 1, " REDIRECTION " ) - printCentred( TermH / 2 - 0, " ComputerCraft Edition " ) - term.setTextColor( colors.yellow ) - printCentred( TermH / 2 + 2, " Click to Begin " ) - os.pullEvent( "mouse_click" ) - end ) + term.setTextColor(colors.red) + printCentred(TermH / 2 - 1, " REDIRECTION ") + printCentred(TermH / 2 - 0, " ComputerCraft Edition ") + term.setTextColor(colors.yellow) + printCentred(TermH / 2 + 2, " Click to Begin ") + os.pullEvent("mouse_click") + end) end --Game-- if ok then - ok, err = pcall( function() + ok, err = pcall(function() local nLevel if sStartLevel then - nLevel = tonumber( sStartLevel ) + nLevel = tonumber(sStartLevel) else nLevel = 1 end @@ -656,36 +656,36 @@ if ok then reset() nLevel = startG(nLevel) end - end ) + end) end --Upsell screen-- if ok then - ok, err = pcall( function() + ok, err = pcall(function() term.setTextColor(colors.white) - term.setBackgroundColor( colors.black ) + term.setBackgroundColor(colors.black) term.clear() drawStars() - term.setTextColor( colors.red ) + term.setTextColor(colors.red) if TermW >= 40 then - printCentred( TermH / 2 - 1, " Thank you for playing Redirection " ) - printCentred( TermH / 2 - 0, " ComputerCraft Edition " ) - printCentred( TermH / 2 + 2, " Check out the full game: " ) - term.setTextColor( colors.yellow ) - printCentred( TermH / 2 + 3, " http://www.redirectiongame.com " ) + printCentred(TermH / 2 - 1, " Thank you for playing Redirection ") + printCentred(TermH / 2 - 0, " ComputerCraft Edition ") + printCentred(TermH / 2 + 2, " Check out the full game: ") + term.setTextColor(colors.yellow) + printCentred(TermH / 2 + 3, " http://www.redirectiongame.com ") else - printCentred( TermH / 2 - 2, " Thank you for " ) - printCentred( TermH / 2 - 1, " playing Redirection " ) - printCentred( TermH / 2 - 0, " ComputerCraft Edition " ) - printCentred( TermH / 2 + 2, " Check out the full game: " ) - term.setTextColor( colors.yellow ) - printCentred( TermH / 2 + 3, " www.redirectiongame.com " ) + printCentred(TermH / 2 - 2, " Thank you for ") + printCentred(TermH / 2 - 1, " playing Redirection ") + printCentred(TermH / 2 - 0, " ComputerCraft Edition ") + printCentred(TermH / 2 + 2, " Check out the full game: ") + term.setTextColor(colors.yellow) + printCentred(TermH / 2 + 3, " www.redirectiongame.com ") end parallel.waitForAll( function() sleep(2) end, - function() os.pullEvent( "mouse_click" ) end + function() os.pullEvent("mouse_click") end ) - end ) + end) end --Clear and exit-- @@ -695,9 +695,9 @@ term.setBackgroundColor(colors.black) term.clear() if not ok then if err == "Terminated" then - print( "Check out the full version of Redirection:" ) - print( "http://www.redirectiongame.com" ) + print("Check out the full version of Redirection:") + print("http://www.redirectiongame.com") else - printError( err ) + printError(err) end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/adventure.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/adventure.lua index 17c2b9a2b..0f08b59be 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/fun/adventure.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/adventure.lua @@ -9,15 +9,15 @@ local tBiomes = { "in frozen tundra", } -local function hasTrees( _nBiome ) +local function hasTrees(_nBiome) return _nBiome <= 3 end -local function hasStone( _nBiome ) +local function hasStone(_nBiome) return _nBiome == 4 end -local function hasRivers( _nBiome ) +local function hasRivers(_nBiome) return _nBiome ~= 3 and _nBiome ~= 5 end @@ -338,14 +338,14 @@ local tDayCycle = { } local function getTimeOfDay() - return math.fmod( math.floor(nTurn / 3), #tDayCycle ) + 1 + return math.fmod(math.floor(nTurn / 3), #tDayCycle) + 1 end local function isSunny() return getTimeOfDay() < 10 end -local function getRoom( x, y, z, dontCreate ) +local function getRoom(x, y, z, dontCreate) tMap[x] = tMap[x] or {} tMap[x][y] = tMap[x][y] or {} if not tMap[x][y][z] and dontCreate ~= true then @@ -360,26 +360,26 @@ local function getRoom( x, y, z, dontCreate ) -- Room is above ground -- Pick biome - room.nBiome = math.random( 1, #tBiomes ) - room.trees = hasTrees( room.nBiome ) + room.nBiome = math.random(1, #tBiomes) + room.trees = hasTrees(room.nBiome) -- Add animals if math.random(1, 3) == 1 then for _ = 1, math.random(1, 2) do - local sAnimal = tAnimals[ math.random( 1, #tAnimals ) ] - room.items[ sAnimal ] = items[ sAnimal ] + local sAnimal = tAnimals[math.random(1, #tAnimals)] + room.items[sAnimal] = items[sAnimal] end end -- Add surface ore - if math.random(1, 5) == 1 or hasStone( room.nBiome ) then - room.items[ "some stone" ] = items[ "some stone" ] + if math.random(1, 5) == 1 or hasStone(room.nBiome) then + room.items["some stone"] = items["some stone"] end if math.random(1, 8) == 1 then - room.items[ "some coal" ] = items[ "some coal" ] + room.items["some coal"] = items["some coal"] end - if math.random(1, 8) == 1 and hasRivers( room.nBiome ) then - room.items[ "a river" ] = items[ "a river" ] + if math.random(1, 8) == 1 and hasRivers(room.nBiome) then + room.items["a river"] = items["a river"] end -- Add exits @@ -390,15 +390,15 @@ local function getRoom( x, y, z, dontCreate ) ["west"] = true, } if math.random(1, 8) == 1 then - room.exits["down"] = true + room.exits.down = true room.items["a cave entrance"] = items["a cave entrance"] end else -- Room is underground -- Add exits - local function tryExit( sDir, sOpp, x, y, z ) - local adj = getRoom( x, y, z, true ) + local function tryExit(sDir, sOpp, x, y, z) + local adj = getRoom(x, y, z, true) if adj then if adj.exits[sOpp] then room.exits[sDir] = true @@ -411,34 +411,34 @@ local function getRoom( x, y, z, dontCreate ) end if y == -1 then - local above = getRoom( x, y + 1, z ) - if above.exits["down"] then - room.exits["up"] = true + local above = getRoom(x, y + 1, z) + if above.exits.down then + room.exits.up = true room.items["an exit to the surface"] = items["an exit to the surface"] end else - tryExit( "up", "down", x, y + 1, z ) + tryExit("up", "down", x, y + 1, z) end if y > -3 then - tryExit( "down", "up", x, y - 1, z ) + tryExit("down", "up", x, y - 1, z) end - tryExit( "east", "west", x - 1, y, z ) - tryExit( "west", "east", x + 1, y, z ) - tryExit( "north", "south", x, y, z + 1 ) - tryExit( "south", "north", x, y, z - 1 ) + tryExit("east", "west", x - 1, y, z) + tryExit("west", "east", x + 1, y, z) + tryExit("north", "south", x, y, z + 1) + tryExit("south", "north", x, y, z - 1) -- Add ores - room.items[ "some stone" ] = items[ "some stone" ] + room.items["some stone"] = items["some stone"] if math.random(1, 3) == 1 then - room.items[ "some coal" ] = items[ "some coal" ] + room.items["some coal"] = items["some coal"] end if math.random(1, 8) == 1 then - room.items[ "some iron" ] = items[ "some iron" ] + room.items["some iron"] = items["some iron"] end if y == -3 and math.random(1, 15) == 1 then - room.items[ "some diamond" ] = items[ "some diamond" ] + room.items["some diamond"] = items["some diamond"] end -- Turn out the lights @@ -448,8 +448,8 @@ local function getRoom( x, y, z, dontCreate ) return tMap[x][y][z] end -local function itemize( t ) - local item = next( t ) +local function itemize(t) + local item = next(t) if item == nil then return "nothing" end @@ -458,9 +458,9 @@ local function itemize( t ) while item do text = text .. item - local nextItem = next( t, item ) + local nextItem = next(t, item) if nextItem ~= nil then - local nextNextItem = next( t, nextItem ) + local nextNextItem = next(t, nextItem) if nextNextItem == nil then text = text .. " and " else @@ -472,13 +472,13 @@ local function itemize( t ) return text end -local function findItem( _tList, _sQuery ) - for sItem, tItem in pairs( _tList ) do +local function findItem(_tList, _sQuery) + for sItem, tItem in pairs(_tList) do if sItem == _sQuery then return sItem end if tItem.aliases ~= nil then - for _, sAlias in pairs( tItem.aliases ) do + for _, sAlias in pairs(tItem.aliases) do if sAlias == _sQuery then return sItem end @@ -606,91 +606,91 @@ local tMatches = { } local commands = {} -local function doCommand( text ) +local function doCommand(text) if text == "" then - commands[ "noinput" ]() + commands.noinput() return end - for sCommand, t in pairs( tMatches ) do - for _, sMatch in pairs( t ) do - local tCaptures = { string.match( text, "^" .. sMatch .. "$" ) } + for sCommand, t in pairs(tMatches) do + for _, sMatch in pairs(t) do + local tCaptures = { string.match(text, "^" .. sMatch .. "$") } if #tCaptures ~= 0 then - local fnCommand = commands[ sCommand ] + local fnCommand = commands[sCommand] if #tCaptures == 1 and tCaptures[1] == sMatch then fnCommand() else - fnCommand( table.unpack( tCaptures ) ) + fnCommand(table.unpack(tCaptures)) end return end end end - commands[ "badinput" ]() + commands.badinput() end function commands.wait() - print( "Time passes..." ) + print("Time passes...") end -function commands.look( _sTarget ) - local room = getRoom( x, y, z ) +function commands.look(_sTarget) + local room = getRoom(x, y, z) if room.dark then - print( "It is pitch dark." ) + print("It is pitch dark.") return end if _sTarget == nil then -- Look at the world if y == 0 then - io.write( "You are standing " .. tBiomes[room.nBiome] .. ". " ) - print( tDayCycle[ getTimeOfDay() ] ) + io.write("You are standing " .. tBiomes[room.nBiome] .. ". ") + print(tDayCycle[getTimeOfDay()]) else - io.write( "You are underground. " ) - if next( room.exits ) ~= nil then - print( "You can travel " .. itemize( room.exits ) .. "." ) + io.write("You are underground. ") + if next(room.exits) ~= nil then + print("You can travel " .. itemize(room.exits) .. ".") else print() end end - if next( room.items ) ~= nil then - print( "There is " .. itemize( room.items ) .. " here." ) + if next(room.items) ~= nil then + print("There is " .. itemize(room.items) .. " here.") end if room.trees then - print( "There are trees here." ) + print("There are trees here.") end else -- Look at stuff if room.trees and (_sTarget == "tree" or _sTarget == "trees") then - print( "The trees look easy to break." ) + print("The trees look easy to break.") elseif _sTarget == "self" or _sTarget == "myself" then - print( "Very handsome." ) + print("Very handsome.") else local tItem = nil - local sItem = findItem( room.items, _sTarget ) + local sItem = findItem(room.items, _sTarget) if sItem then tItem = room.items[sItem] else - sItem = findItem( inventory, _sTarget ) + sItem = findItem(inventory, _sTarget) if sItem then tItem = inventory[sItem] end end if tItem then - print( tItem.desc or "You see nothing special about " .. sItem .. "." ) + print(tItem.desc or "You see nothing special about " .. sItem .. ".") else - print( "You don't see any " .. _sTarget .. " here." ) + print("You don't see any " .. _sTarget .. " here.") end end end end -function commands.go( _sDir ) - local room = getRoom( x, y, z ) +function commands.go(_sDir) + local room = getRoom(x, y, z) if _sDir == nil then - print( "Go where?" ) + print("Go where?") return end @@ -700,7 +700,7 @@ function commands.go( _sDir ) if nGoWest > #tGoWest then nGoWest = 1 end - print( tGoWest[ nGoWest ] ) + print(tGoWest[nGoWest]) else if nGoWest > 0 or nTurn > 6 then nGoWest = nil @@ -709,7 +709,7 @@ function commands.go( _sDir ) end if room.exits[_sDir] == nil then - print( "You can't go that way." ) + print("You can't go that way.") return end @@ -726,98 +726,98 @@ function commands.go( _sDir ) elseif _sDir == "down" then y = y - 1 else - print( "I don't understand that direction." ) + print("I don't understand that direction.") return end nTimeInRoom = 0 - doCommand( "look" ) + doCommand("look") end -function commands.dig( _sDir, _sTool ) - local room = getRoom( x, y, z ) +function commands.dig(_sDir, _sTool) + local room = getRoom(x, y, z) if _sDir == nil then - print( "Dig where?" ) + print("Dig where?") return end local sTool = nil local tTool = nil if _sTool ~= nil then - sTool = findItem( inventory, _sTool ) + sTool = findItem(inventory, _sTool) if not sTool then - print( "You're not carrying a " .. _sTool .. "." ) + print("You're not carrying a " .. _sTool .. ".") return end - tTool = inventory[ sTool ] + tTool = inventory[sTool] end - local bActuallyDigging = room.exits[ _sDir ] ~= true + local bActuallyDigging = room.exits[_sDir] ~= true if bActuallyDigging then if sTool == nil or tTool.toolType ~= "pick" then - print( "You need to use a pickaxe to dig through stone." ) + print("You need to use a pickaxe to dig through stone.") return end end if _sDir == "north" then - room.exits["north"] = true + room.exits.north = true z = z + 1 - getRoom( x, y, z ).exits["south"] = true + getRoom(x, y, z).exits.south = true elseif _sDir == "south" then - room.exits["south"] = true + room.exits.south = true z = z - 1 - getRoom( x, y, z ).exits["north"] = true + getRoom(x, y, z).exits.north = true elseif _sDir == "east" then - room.exits["east"] = true + room.exits.east = true x = x - 1 - getRoom( x, y, z ).exits["west"] = true + getRoom(x, y, z).exits.west = true elseif _sDir == "west" then - room.exits["west"] = true + room.exits.west = true x = x + 1 - getRoom( x, y, z ).exits["east"] = true + getRoom(x, y, z).exits.east = true elseif _sDir == "up" then if y == 0 then - print( "You can't dig that way." ) + print("You can't dig that way.") return end - room.exits["up"] = true + room.exits.up = true if y == -1 then - room.items[ "an exit to the surface" ] = items[ "an exit to the surface" ] + room.items["an exit to the surface"] = items["an exit to the surface"] end y = y + 1 - room = getRoom( x, y, z ) - room.exits["down"] = true + room = getRoom(x, y, z) + room.exits.down = true if y == 0 then - room.items[ "a cave entrance" ] = items[ "a cave entrance" ] + room.items["a cave entrance"] = items["a cave entrance"] end elseif _sDir == "down" then if y <= -3 then - print( "You hit bedrock." ) + print("You hit bedrock.") return end - room.exits["down"] = true + room.exits.down = true if y == 0 then - room.items[ "a cave entrance" ] = items[ "a cave entrance" ] + room.items["a cave entrance"] = items["a cave entrance"] end y = y - 1 - room = getRoom( x, y, z ) - room.exits["up"] = true + room = getRoom(x, y, z) + room.exits.up = true if y == -1 then - room.items[ "an exit to the surface" ] = items[ "an exit to the surface" ] + room.items["an exit to the surface"] = items["an exit to the surface"] end else - print( "I don't understand that direction." ) + print("I don't understand that direction.") return end @@ -825,183 +825,183 @@ function commands.dig( _sDir, _sTool ) if bActuallyDigging then if _sDir == "down" and y == -1 or _sDir == "up" and y == 0 then - inventory[ "some dirt" ] = items[ "some dirt" ] - inventory[ "some stone" ] = items[ "some stone" ] - print( "You dig " .. _sDir .. " using " .. sTool .. " and collect some dirt and stone." ) + inventory["some dirt"] = items["some dirt"] + inventory["some stone"] = items["some stone"] + print("You dig " .. _sDir .. " using " .. sTool .. " and collect some dirt and stone.") else - inventory[ "some stone" ] = items[ "some stone" ] - print( "You dig " .. _sDir .. " using " .. sTool .. " and collect some stone." ) + inventory["some stone"] = items["some stone"] + print("You dig " .. _sDir .. " using " .. sTool .. " and collect some stone.") end end nTimeInRoom = 0 - doCommand( "look" ) + doCommand("look") end function commands.inventory() - print( "You are carrying " .. itemize( inventory ) .. "." ) + print("You are carrying " .. itemize(inventory) .. ".") end -function commands.drop( _sItem ) +function commands.drop(_sItem) if _sItem == nil then - print( "Drop what?" ) + print("Drop what?") return end - local room = getRoom( x, y, z ) - local sItem = findItem( inventory, _sItem ) + local room = getRoom(x, y, z) + local sItem = findItem(inventory, _sItem) if sItem then - local tItem = inventory[ sItem ] + local tItem = inventory[sItem] if tItem.droppable == false then - print( "You can't drop that." ) + print("You can't drop that.") else - room.items[ sItem ] = tItem - inventory[ sItem ] = nil - print( "Dropped." ) + room.items[sItem] = tItem + inventory[sItem] = nil + print("Dropped.") end else - print( "You don't have a " .. _sItem .. "." ) + print("You don't have a " .. _sItem .. ".") end end -function commands.place( _sItem ) +function commands.place(_sItem) if _sItem == nil then - print( "Place what?" ) + print("Place what?") return end if _sItem == "torch" or _sItem == "a torch" then - local room = getRoom( x, y, z ) + local room = getRoom(x, y, z) if inventory["some torches"] or inventory["a torch"] then inventory["a torch"] = nil room.items["a torch"] = items["a torch"] if room.dark then - print( "The cave lights up under the torchflame." ) + print("The cave lights up under the torchflame.") room.dark = false elseif y == 0 and not isSunny() then - print( "The night gets a little brighter." ) + print("The night gets a little brighter.") else - print( "Placed." ) + print("Placed.") end else - print( "You don't have torches." ) + print("You don't have torches.") end return end - commands.drop( _sItem ) + commands.drop(_sItem) end -function commands.take( _sItem ) +function commands.take(_sItem) if _sItem == nil then - print( "Take what?" ) + print("Take what?") return end - local room = getRoom( x, y, z ) - local sItem = findItem( room.items, _sItem ) + local room = getRoom(x, y, z) + local sItem = findItem(room.items, _sItem) if sItem then - local tItem = room.items[ sItem ] + local tItem = room.items[sItem] if tItem.heavy == true then - print( "You can't carry " .. sItem .. "." ) + print("You can't carry " .. sItem .. ".") elseif tItem.ore == true then - print( "You need to mine this ore." ) + print("You need to mine this ore.") else if tItem.infinite ~= true then - room.items[ sItem ] = nil + room.items[sItem] = nil end - inventory[ sItem ] = tItem + inventory[sItem] = tItem if inventory["some torches"] and inventory["a torch"] then inventory["a torch"] = nil end if sItem == "a torch" and y < 0 then room.dark = true - print( "The cave plunges into darkness." ) + print("The cave plunges into darkness.") else - print( "Taken." ) + print("Taken.") end end else - print( "You don't see a " .. _sItem .. " here." ) + print("You don't see a " .. _sItem .. " here.") end end -function commands.mine( _sItem, _sTool ) +function commands.mine(_sItem, _sTool) if _sItem == nil then - print( "Mine what?" ) + print("Mine what?") return end if _sTool == nil then - print( "Mine " .. _sItem .. " with what?" ) + print("Mine " .. _sItem .. " with what?") return end - commands.cbreak( _sItem, _sTool ) + commands.cbreak(_sItem, _sTool) end -function commands.attack( _sItem, _sTool ) +function commands.attack(_sItem, _sTool) if _sItem == nil then - print( "Attack what?" ) + print("Attack what?") return end - commands.cbreak( _sItem, _sTool ) + commands.cbreak(_sItem, _sTool) end -function commands.cbreak( _sItem, _sTool ) +function commands.cbreak(_sItem, _sTool) if _sItem == nil then - print( "Break what?" ) + print("Break what?") return end local sTool = nil if _sTool ~= nil then - sTool = findItem( inventory, _sTool ) + sTool = findItem(inventory, _sTool) if sTool == nil then - print( "You're not carrying a " .. _sTool .. "." ) + print("You're not carrying a " .. _sTool .. ".") return end end - local room = getRoom( x, y, z ) + local room = getRoom(x, y, z) if _sItem == "tree" or _sItem == "trees" or _sItem == "a tree" then - print( "The tree breaks into blocks of wood, which you pick up." ) - inventory[ "some wood" ] = items[ "some wood" ] + print("The tree breaks into blocks of wood, which you pick up.") + inventory["some wood"] = items["some wood"] return elseif _sItem == "self" or _sItem == "myself" then if term.isColour() then - term.setTextColour( colours.red ) + term.setTextColour(colours.red) end - print( "You have died." ) - print( "Score: &e0" ) - term.setTextColour( colours.white ) + print("You have died.") + print("Score: &e0") + term.setTextColour(colours.white) bRunning = false return end - local sItem = findItem( room.items, _sItem ) + local sItem = findItem(room.items, _sItem) if sItem then - local tItem = room.items[ sItem ] + local tItem = room.items[sItem] if tItem.ore == true then -- Breaking ore if not sTool then - print( "You need a tool to break this ore." ) + print("You need a tool to break this ore.") return end - local tTool = inventory[ sTool ] + local tTool = inventory[sTool] if tTool.tool then if tTool.toolLevel < tItem.toolLevel then - print( sTool .. " is not strong enough to break this ore." ) + print(sTool .. " is not strong enough to break this ore.") elseif tTool.toolType ~= tItem.toolType then - print( "You need a different kind of tool to break this ore." ) + print("You need a different kind of tool to break this ore.") else - print( "The ore breaks, dropping " .. sItem .. ", which you pick up." ) - inventory[ sItem ] = items[ sItem ] + print("The ore breaks, dropping " .. sItem .. ", which you pick up.") + inventory[sItem] = items[sItem] if tItem.infinite ~= true then - room.items[ sItem ] = nil + room.items[sItem] = nil end end else - print( "You can't break " .. sItem .. " with " .. sTool .. ".") + print("You can't break " .. sItem .. " with " .. sTool .. ".") end elseif tItem.creature == true then @@ -1009,21 +1009,21 @@ function commands.cbreak( _sItem, _sTool ) local toolLevel = 0 local tTool = nil if sTool then - tTool = inventory[ sTool ] + tTool = inventory[sTool] if tTool.toolType == "sword" then toolLevel = tTool.toolLevel end end local tChances = { 0.2, 0.4, 0.55, 0.8, 1 } - if math.random() <= tChances[ toolLevel + 1 ] then - room.items[ sItem ] = nil - print( "The " .. tItem.aliases[1] .. " dies." ) + if math.random() <= tChances[toolLevel + 1] then + room.items[sItem] = nil + print("The " .. tItem.aliases[1] .. " dies.") if tItem.drops then - for _, sDrop in pairs( tItem.drops ) do + for _, sDrop in pairs(tItem.drops) do if not room.items[sDrop] then - print( "The " .. tItem.aliases[1] .. " dropped " .. sDrop .. "." ) + print("The " .. tItem.aliases[1] .. " dropped " .. sDrop .. ".") room.items[sDrop] = items[sDrop] end end @@ -1033,112 +1033,112 @@ function commands.cbreak( _sItem, _sTool ) room.nMonsters = room.nMonsters - 1 end else - print( "The " .. tItem.aliases[1] .. " is injured by your blow." ) + print("The " .. tItem.aliases[1] .. " is injured by your blow.") end if tItem.hitDrops then - for _, sDrop in pairs( tItem.hitDrops ) do + for _, sDrop in pairs(tItem.hitDrops) do if not room.items[sDrop] then - print( "The " .. tItem.aliases[1] .. " dropped " .. sDrop .. "." ) + print("The " .. tItem.aliases[1] .. " dropped " .. sDrop .. ".") room.items[sDrop] = items[sDrop] end end end else - print( "You can't break " .. sItem .. "." ) + print("You can't break " .. sItem .. ".") end else - print( "You don't see a " .. _sItem .. " here." ) + print("You don't see a " .. _sItem .. " here.") end end -function commands.craft( _sItem ) +function commands.craft(_sItem) if _sItem == nil then - print( "Craft what?" ) + print("Craft what?") return end if _sItem == "computer" or _sItem == "a computer" then - print( "By creating a computer in a computer in a computer, you tear a hole in the spacetime continuum from which no mortal being can escape." ) + print("By creating a computer in a computer in a computer, you tear a hole in the spacetime continuum from which no mortal being can escape.") if term.isColour() then - term.setTextColour( colours.red ) + term.setTextColour(colours.red) end - print( "You have died." ) - print( "Score: &e0" ) - term.setTextColour( colours.white ) + print("You have died.") + print("Score: &e0") + term.setTextColour(colours.white) bRunning = false return end - local sItem = findItem( items, _sItem ) - local tRecipe = sItem and tRecipes[ sItem ] or nil + local sItem = findItem(items, _sItem) + local tRecipe = sItem and tRecipes[sItem] or nil if tRecipe then - for _, sReq in ipairs( tRecipe ) do + for _, sReq in ipairs(tRecipe) do if inventory[sReq] == nil then - print( "You don't have the items you need to craft " .. sItem .. "." ) + print("You don't have the items you need to craft " .. sItem .. ".") return end end - for _, sReq in ipairs( tRecipe ) do + for _, sReq in ipairs(tRecipe) do inventory[sReq] = nil end - inventory[ sItem ] = items[ sItem ] + inventory[sItem] = items[sItem] if inventory["some torches"] and inventory["a torch"] then inventory["a torch"] = nil end - print( "Crafted." ) + print("Crafted.") else - print( "You don't know how to make " .. (sItem or _sItem) .. "." ) + print("You don't know how to make " .. (sItem or _sItem) .. ".") end end -function commands.build( _sThing, _sMaterial ) +function commands.build(_sThing, _sMaterial) if _sThing == nil then - print( "Build what?" ) + print("Build what?") return end local sMaterial = nil if _sMaterial == nil then - for sItem, tItem in pairs( inventory ) do + for sItem, tItem in pairs(inventory) do if tItem.material then sMaterial = sItem break end end if sMaterial == nil then - print( "You don't have any building materials." ) + print("You don't have any building materials.") return end else - sMaterial = findItem( inventory, _sMaterial ) + sMaterial = findItem(inventory, _sMaterial) if not sMaterial then - print( "You don't have any " .. _sMaterial ) + print("You don't have any " .. _sMaterial) return end if inventory[sMaterial].material ~= true then - print( sMaterial .. " is not a good building material." ) + print(sMaterial .. " is not a good building material.") return end end local alias = nil if string.sub(_sThing, 1, 1) == "a" then - alias = string.match( _sThing, "a ([%a ]+)" ) + alias = string.match(_sThing, "a ([%a ]+)") end - local room = getRoom( x, y, z ) + local room = getRoom(x, y, z) inventory[sMaterial] = nil - room.items[ _sThing ] = { + room.items[_sThing] = { heavy = true, aliases = { alias }, desc = "As you look at your creation (made from " .. sMaterial .. "), you feel a swelling sense of pride.", } - print( "Your construction is complete." ) + print("Your construction is complete.") end function commands.help() @@ -1147,32 +1147,32 @@ function commands.help() "To get around the world, type actions, and the adventure will " .. "be read back to you. The actions availiable to you are go, look, inspect, inventory, " .. "take, drop, place, punch, attack, mine, dig, craft, build, eat and exit." - print( sText ) + print(sText) end -function commands.eat( _sItem ) +function commands.eat(_sItem) if _sItem == nil then - print( "Eat what?" ) + print("Eat what?") return end - local sItem = findItem( inventory, _sItem ) + local sItem = findItem(inventory, _sItem) if not sItem then - print( "You don't have any " .. _sItem .. "." ) + print("You don't have any " .. _sItem .. ".") return end local tItem = inventory[sItem] if tItem.food then - print( "That was delicious!" ) + print("That was delicious!") inventory[sItem] = nil if bInjured then - print( "You are no longer injured." ) + print("You are no longer injured.") bInjured = false end else - print( "You can't eat " .. sItem .. "." ) + print("You can't eat " .. sItem .. ".") end end @@ -1195,7 +1195,7 @@ function commands.badinput() "That doesn't make any sense.", "What?", } - print( tResponses[ math.random(1, #tResponses) ] ) + print(tResponses[math.random(1, #tResponses)]) end function commands.noinput() @@ -1206,7 +1206,7 @@ function commands.noinput() "Don't be shy.", "Use your words.", } - print( tResponses[ math.random(1, #tResponses) ] ) + print(tResponses[math.random(1, #tResponses)]) end local function simulate() @@ -1218,20 +1218,20 @@ local function simulate() for sz = -2, 2 do local h = y + sy if h >= -3 and h <= 0 then - local room = getRoom( x + sx, h, z + sz ) + local room = getRoom(x + sx, h, z + sz) -- Spawn monsters if room.nMonsters < 2 and (h == 0 and not isSunny() and not room.items["a torch"] or room.dark) and math.random(1, 6) == 1 then - local sMonster = tMonsters[ math.random(1, #tMonsters) ] - if room.items[ sMonster ] == nil then - room.items[ sMonster ] = items[ sMonster ] + local sMonster = tMonsters[math.random(1, #tMonsters)] + if room.items[sMonster] == nil then + room.items[sMonster] = items[sMonster] room.nMonsters = room.nMonsters + 1 if sx == 0 and sy == 0 and sz == 0 and not room.dark then - print( "From the shadows, " .. sMonster .. " appears." ) + print("From the shadows, " .. sMonster .. " appears.") bNewMonstersThisRoom = true end end @@ -1239,11 +1239,11 @@ local function simulate() -- Burn monsters if h == 0 and isSunny() then - for _, sMonster in ipairs( tMonsters ) do + for _, sMonster in ipairs(tMonsters) do if room.items[sMonster] and items[sMonster].nocturnal then room.items[sMonster] = nil if sx == 0 and sy == 0 and sz == 0 and not room.dark then - print( "With the sun high in the sky, the " .. items[sMonster].aliases[1] .. " bursts into flame and dies." ) + print("With the sun high in the sky, the " .. items[sMonster].aliases[1] .. " bursts into flame and dies.") end room.nMonsters = room.nMonsters - 1 end @@ -1255,35 +1255,35 @@ local function simulate() end -- Make monsters attack - local room = getRoom( x, y, z ) + local room = getRoom(x, y, z) if nTimeInRoom >= 2 and not bNewMonstersThisRoom then - for _, sMonster in ipairs( tMonsters ) do + for _, sMonster in ipairs(tMonsters) do if room.items[sMonster] then if math.random(1, 4) == 1 and not (y == 0 and isSunny() and sMonster == "a spider") then if sMonster == "a creeper" then if room.dark then - print( "A creeper explodes." ) + print("A creeper explodes.") else - print( "The creeper explodes." ) + print("The creeper explodes.") end room.items[sMonster] = nil room.nMonsters = room.nMonsters - 1 else if room.dark then - print( "A " .. items[sMonster].aliases[1] .. " attacks you." ) + print("A " .. items[sMonster].aliases[1] .. " attacks you.") else - print( "The " .. items[sMonster].aliases[1] .. " attacks you." ) + print("The " .. items[sMonster].aliases[1] .. " attacks you.") end end if bInjured then if term.isColour() then - term.setTextColour( colours.red ) + term.setTextColour(colours.red) end - print( "You have died." ) - print( "Score: &e0" ) - term.setTextColour( colours.white ) + print("You have died.") + print("Score: &e0") + term.setTextColour(colours.white) bRunning = false return else @@ -1299,10 +1299,10 @@ local function simulate() -- Always print this if bInjured then if term.isColour() then - term.setTextColour( colours.red ) + term.setTextColour(colours.red) end - print( "You are injured." ) - term.setTextColour( colours.white ) + print("You are injured.") + term.setTextColour(colours.white) end -- Advance time @@ -1310,19 +1310,19 @@ local function simulate() nTimeInRoom = nTimeInRoom + 1 end -doCommand( "look" ) +doCommand("look") simulate() local tCommandHistory = {} while bRunning do if term.isColour() then - term.setTextColour( colours.yellow ) + term.setTextColour(colours.yellow) end - write( "? " ) - term.setTextColour( colours.white ) + write("? ") + term.setTextColour(colours.white) - local sRawLine = read( nil, tCommandHistory ) - table.insert( tCommandHistory, sRawLine ) + local sRawLine = read(nil, tCommandHistory) + table.insert(tCommandHistory, sRawLine) local sLine = nil for match in string.gmatch(sRawLine, "%a+") do @@ -1333,7 +1333,7 @@ while bRunning do end end - doCommand( sLine or "" ) + doCommand(sLine or "") if bRunning then simulate() end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/dj.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/dj.lua index 78b259fe0..322b4a887 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/fun/dj.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/dj.lua @@ -1,10 +1,10 @@ local tArgs = { ... } local function printUsage() - print( "Usages:") - print( "dj play" ) - print( "dj play " ) - print( "dj stop" ) + print("Usages:") + print("dj play") + print("dj play ") + print("dj stop") end if #tArgs > 2 then @@ -23,24 +23,24 @@ elseif sCommand == "play" or sCommand == nil then if sName == nil then -- No disc specified, pick one at random local tNames = {} - for _, sName in ipairs( peripheral.getNames() ) do - if disk.isPresent( sName ) and disk.hasAudio( sName ) then - table.insert( tNames, sName ) + for _, sName in ipairs(peripheral.getNames()) do + if disk.isPresent(sName) and disk.hasAudio(sName) then + table.insert(tNames, sName) end end if #tNames == 0 then - print( "No Music Discs in attached disk drives" ) + print("No Music Discs in attached disk drives") return end - sName = tNames[ math.random(1, #tNames) ] + sName = tNames[math.random(1, #tNames)] end -- Play the disc - if disk.isPresent( sName ) and disk.hasAudio( sName ) then - print( "Playing " .. disk.getAudioTitle( sName ) ) - disk.playAudio( sName ) + if disk.isPresent(sName) and disk.hasAudio(sName) then + print("Playing " .. disk.getAudioTitle(sName)) + disk.playAudio(sName) else - print( "No Music Disc in disk drive: " .. sName ) + print("No Music Disc in disk drive: " .. sName) return end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/hello.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/hello.lua index d22399410..0afdf9e77 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/fun/hello.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/hello.lua @@ -1,5 +1,5 @@ if term.isColour() then - term.setTextColour( 2 ^ math.random(0, 15) ) + term.setTextColour(2 ^ math.random(0, 15)) end -textutils.slowPrint( "Hello World!" ) -term.setTextColour( colours.white ) +textutils.slowPrint("Hello World!") +term.setTextColour(colours.white) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/worm.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/worm.lua index 507763cb4..fe753b032 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/fun/worm.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/worm.lua @@ -15,11 +15,11 @@ else fruitColour = colours.white end -local function printCentred( y, s ) +local function printCentred(y, s) local x = math.floor((w - #s) / 2) term.setCursorPos(x, y) --term.clearLine() - term.write( s ) + term.write(s) end local xVel, yVel = 1, 0 @@ -65,9 +65,9 @@ local function addFruit() if fruit.snake == nil and fruit.wall == nil and fruit.fruit == nil then screen[x][y] = { fruit = true } term.setCursorPos(x, y) - term.setBackgroundColour( fruitColour ) + term.setBackgroundColour(fruitColour) term.write(" ") - term.setBackgroundColour( colours.black ) + term.setBackgroundColour(colours.black) break end end @@ -79,23 +79,23 @@ local function addFruit() end local function drawMenu() - term.setTextColour( headingColour ) + term.setTextColour(headingColour) term.setCursorPos(1, 1) - term.write( "SCORE " ) + term.write("SCORE ") - term.setTextColour( textColour ) + term.setTextColour(textColour) term.setCursorPos(7, 1) - term.write( tostring(nScore) ) + term.write(tostring(nScore)) - term.setTextColour( headingColour ) + term.setTextColour(headingColour) term.setCursorPos(w - 11, 1) - term.write( "DIFFICULTY ") + term.write("DIFFICULTY ") - term.setTextColour( textColour ) + term.setTextColour(textColour) term.setCursorPos(w, 1) - term.write( tostring(nDifficulty or "?") ) + term.write(tostring(nDifficulty or "?")) - term.setTextColour( colours.white ) + term.setTextColour(colours.white) end local function update( ) @@ -150,9 +150,9 @@ local function update( ) end term.setCursorPos(xPos, yPos) - term.setBackgroundColour( wormColour ) + term.setBackgroundColour(wormColour) term.write(" ") - term.setBackgroundColour( colours.black ) + term.setBackgroundColour(colours.black) drawMenu() end @@ -163,29 +163,29 @@ local function drawFrontend() --term.setTextColour( titleColour ) --printCentred( math.floor(h/2) - 4, " W O R M " ) - term.setTextColour( headingColour ) - printCentred( math.floor(h / 2) - 3, "" ) - printCentred( math.floor(h / 2) - 2, " SELECT DIFFICULTY " ) - printCentred( math.floor(h / 2) - 1, "" ) + term.setTextColour(headingColour) + printCentred(math.floor(h / 2) - 3, "") + printCentred(math.floor(h / 2) - 2, " SELECT DIFFICULTY ") + printCentred(math.floor(h / 2) - 1, "") - printCentred( math.floor(h / 2) + 0, " " ) - printCentred( math.floor(h / 2) + 1, " " ) - printCentred( math.floor(h / 2) + 2, " " ) - printCentred( math.floor(h / 2) - 1 + nDifficulty, " [ ] " ) + printCentred(math.floor(h / 2) + 0, " ") + printCentred(math.floor(h / 2) + 1, " ") + printCentred(math.floor(h / 2) + 2, " ") + printCentred(math.floor(h / 2) - 1 + nDifficulty, " [ ] ") - term.setTextColour( textColour ) - printCentred( math.floor(h / 2) + 0, "EASY" ) - printCentred( math.floor(h / 2) + 1, "MEDIUM" ) - printCentred( math.floor(h / 2) + 2, "HARD" ) - printCentred( math.floor(h / 2) + 3, "" ) + term.setTextColour(textColour) + printCentred(math.floor(h / 2) + 0, "EASY") + printCentred(math.floor(h / 2) + 1, "MEDIUM") + printCentred(math.floor(h / 2) + 2, "HARD") + printCentred(math.floor(h / 2) + 3, "") - term.setTextColour( colours.white ) + term.setTextColour(colours.white) end drawMenu() drawFrontend() while true do - local _, key = os.pullEvent( "key" ) + local _, key = os.pullEvent("key") if key == keys.up or key == keys.w then -- Up if nDifficulty > 1 then @@ -226,7 +226,7 @@ while bRunning do local event, p1 = os.pullEvent() if event == "timer" and p1 == timer then timer = os.startTimer(nInterval) - update( false ) + update(false) elseif event == "key" then local key = p1 @@ -257,24 +257,24 @@ while bRunning do end -- Display the gameover screen -term.setTextColour( headingColour ) -printCentred( math.floor(h / 2) - 2, " " ) -printCentred( math.floor(h / 2) - 1, " G A M E O V E R " ) +term.setTextColour(headingColour) +printCentred(math.floor(h / 2) - 2, " ") +printCentred(math.floor(h / 2) - 1, " G A M E O V E R ") -term.setTextColour( textColour ) -printCentred( math.floor(h / 2) + 0, " " ) -printCentred( math.floor(h / 2) + 1, " FINAL SCORE " .. nScore .. " " ) -printCentred( math.floor(h / 2) + 2, " " ) -term.setTextColour( colours.white ) +term.setTextColour(textColour) +printCentred(math.floor(h / 2) + 0, " ") +printCentred(math.floor(h / 2) + 1, " FINAL SCORE " .. nScore .. " ") +printCentred(math.floor(h / 2) + 2, " ") +term.setTextColour(colours.white) local timer = os.startTimer(2.5) repeat local e, p = os.pullEvent() if e == "timer" and p == timer then - term.setTextColour( textColour ) - printCentred( math.floor(h / 2) + 2, " PRESS ANY KEY " ) - printCentred( math.floor(h / 2) + 3, " " ) - term.setTextColour( colours.white ) + term.setTextColour(textColour) + printCentred(math.floor(h / 2) + 2, " PRESS ANY KEY ") + printCentred(math.floor(h / 2) + 3, " ") + term.setTextColour(colours.white) end until e == "char" diff --git a/src/main/resources/data/computercraft/lua/rom/programs/gps.lua b/src/main/resources/data/computercraft/lua/rom/programs/gps.lua index c5556c079..9e1ff0538 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/gps.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/gps.lua @@ -1,9 +1,9 @@ local function printUsage() - print( "Usages:" ) - print( "gps host" ) - print( "gps host " ) - print( "gps locate" ) + print("Usages:") + print("gps host") + print("gps host ") + print("gps locate") end local tArgs = { ... } @@ -16,27 +16,27 @@ end if sCommand == "locate" then -- "gps locate" -- Just locate this computer (this will print the results) - gps.locate( 2, true ) + gps.locate(2, true) elseif sCommand == "host" then -- "gps host" -- Act as a GPS host if pocket then - print( "GPS Hosts must be stationary" ) + print("GPS Hosts must be stationary") return end -- Find a modem local sModemSide = nil - for _, sSide in ipairs( rs.getSides() ) do - if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then + for _, sSide in ipairs(rs.getSides()) do + if peripheral.getType(sSide) == "modem" and peripheral.call(sSide, "isWireless") then sModemSide = sSide break end end if sModemSide == nil then - print( "No wireless modems found. 1 required." ) + print("No wireless modems found. 1 required.") return end @@ -51,31 +51,31 @@ elseif sCommand == "host" then printUsage() return end - print( "Position is " .. x .. "," .. y .. "," .. z ) + print("Position is " .. x .. "," .. y .. "," .. z) else -- Position is to be determined using locate - x, y, z = gps.locate( 2, true ) + x, y, z = gps.locate(2, true) if x == nil then - print( "Run \"gps host \" to set position manually" ) + print("Run \"gps host \" to set position manually") return end end -- Open a channel - local modem = peripheral.wrap( sModemSide ) - print( "Opening channel on modem " .. sModemSide ) - modem.open( gps.CHANNEL_GPS ) + local modem = peripheral.wrap(sModemSide) + print("Opening channel on modem " .. sModemSide) + modem.open(gps.CHANNEL_GPS) -- Serve requests indefinately local nServed = 0 while true do - local e, p1, p2, p3, p4, p5 = os.pullEvent( "modem_message" ) + local e, p1, p2, p3, p4, p5 = os.pullEvent("modem_message") if e == "modem_message" then -- We received a message from a modem local sSide, sChannel, sReplyChannel, sMessage, nDistance = p1, p2, p3, p4, p5 if sSide == sModemSide and sChannel == gps.CHANNEL_GPS and sMessage == "PING" and nDistance then -- We received a ping message on the GPS channel, send a response - modem.transmit( sReplyChannel, gps.CHANNEL_GPS, { x, y, z } ) + modem.transmit(sReplyChannel, gps.CHANNEL_GPS, { x, y, z }) -- Print the number of requests handled nServed = nServed + 1 @@ -83,7 +83,7 @@ elseif sCommand == "host" then local _, y = term.getCursorPos() term.setCursorPos(1, y - 1) end - print( nServed .. " GPS requests served" ) + print(nServed .. " GPS requests served") end end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/help.lua b/src/main/resources/data/computercraft/lua/rom/programs/help.lua index c8653616a..63ece3ab4 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/help.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/help.lua @@ -7,20 +7,20 @@ else end if sTopic == "index" then - print( "Help topics available:" ) + print("Help topics available:") local tTopics = help.topics() - textutils.pagedTabulate( tTopics ) + textutils.pagedTabulate(tTopics) return end -local sFile = help.lookup( sTopic ) -local file = sFile ~= nil and io.open( sFile ) or nil +local sFile = help.lookup(sTopic) +local file = sFile ~= nil and io.open(sFile) or nil if file then local sContents = file:read("*a") file:close() local _, nHeight = term.getSize() - textutils.pagedPrint( sContents, nHeight - 3 ) + textutils.pagedPrint(sContents, nHeight - 3) else - print( "No help available" ) + print("No help available") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/http/pastebin.lua b/src/main/resources/data/computercraft/lua/rom/programs/http/pastebin.lua index 3e28a2f7a..a45ea1a2a 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/http/pastebin.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/http/pastebin.lua @@ -1,9 +1,9 @@ local function printUsage() - print( "Usages:" ) - print( "pastebin put " ) - print( "pastebin get " ) - print( "pastebin run " ) + print("Usages:") + print("pastebin put ") + print("pastebin get ") + print("pastebin run ") end local tArgs = { ... } @@ -13,8 +13,8 @@ if #tArgs < 2 then end if not http then - printError( "Pastebin requires http API" ) - printError( "Set http_enable to true in ComputerCraft.cfg" ) + printError("Pastebin requires the http API") + printError("Set http.enabled to true in CC: Tweaked's config") return end @@ -29,7 +29,7 @@ local function extractId(paste) } for i = 1, #patterns do - local code = paste:match( patterns[i] ) + local code = paste:match(patterns[i]) if code then return code end end @@ -37,36 +37,36 @@ local function extractId(paste) end local function get(url) - local paste = extractId( url ) + local paste = extractId(url) if not paste then - io.stderr:write( "Invalid pastebin code.\n" ) - io.write( "The code is the ID at the end of the pastebin.com URL.\n" ) + io.stderr:write("Invalid pastebin code.\n") + io.write("The code is the ID at the end of the pastebin.com URL.\n") return end - write( "Connecting to pastebin.com... " ) + write("Connecting to pastebin.com... ") -- Add a cache buster so that spam protection is re-checked local cacheBuster = ("%x"):format(math.random(0, 2 ^ 30)) local response, err = http.get( - "https://pastebin.com/raw/" .. textutils.urlEncode( paste ) .. "?cb=" .. cacheBuster + "https://pastebin.com/raw/" .. textutils.urlEncode(paste) .. "?cb=" .. cacheBuster ) if response then -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html local headers = response.getResponseHeaders() - if not headers["Content-Type"] or not headers["Content-Type"]:find( "^text/plain" ) then - io.stderr:write( "Failed.\n" ) - print( "Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode( paste ) ) + if not headers["Content-Type"] or not headers["Content-Type"]:find("^text/plain") then + io.stderr:write("Failed.\n") + print("Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode(paste)) return end - print( "Success." ) + print("Success.") local sResponse = response.readAll() response.close() return sResponse else - io.stderr:write( "Failed.\n" ) + io.stderr:write("Failed.\n") print(err) end end @@ -76,20 +76,20 @@ if sCommand == "put" then -- Upload a file to pastebin.com -- Determine file to upload local sFile = tArgs[2] - local sPath = shell.resolve( sFile ) - if not fs.exists( sPath ) or fs.isDir( sPath ) then - print( "No such file" ) + local sPath = shell.resolve(sFile) + if not fs.exists(sPath) or fs.isDir(sPath) then + print("No such file") return end -- Read in the file - local sName = fs.getName( sPath ) - local file = fs.open( sPath, "r" ) + local sName = fs.getName(sPath) + local file = fs.open(sPath, "r") local sText = file.readAll() file.close() -- POST the contents to pastebin - write( "Connecting to pastebin.com... " ) + write("Connecting to pastebin.com... ") local key = "0ec2eb25b6166c0c27a394ae118ad829" local response = http.post( "https://pastebin.com/api/api_post.php", @@ -101,17 +101,17 @@ if sCommand == "put" then ) if response then - print( "Success." ) + print("Success.") local sResponse = response.readAll() response.close() - local sCode = string.match( sResponse, "[^/]+$" ) - print( "Uploaded as " .. sResponse ) - print( "Run \"pastebin get " .. sCode .. "\" to download anywhere" ) + local sCode = string.match(sResponse, "[^/]+$") + print("Uploaded as " .. sResponse) + print("Run \"pastebin get " .. sCode .. "\" to download anywhere") else - print( "Failed." ) + print("Failed.") end elseif sCommand == "get" then @@ -124,20 +124,20 @@ elseif sCommand == "get" then -- Determine file to download local sCode = tArgs[2] local sFile = tArgs[3] - local sPath = shell.resolve( sFile ) - if fs.exists( sPath ) then - print( "File already exists" ) + local sPath = shell.resolve(sFile) + if fs.exists(sPath) then + print("File already exists") return end -- GET the contents from pastebin local res = get(sCode) if res then - local file = fs.open( sPath, "w" ) - file.write( res ) + local file = fs.open(sPath, "w") + file.write(res) file.close() - print( "Downloaded as " .. sFile ) + print("Downloaded as " .. sFile) end elseif sCommand == "run" then local sCode = tArgs[2] @@ -146,12 +146,12 @@ elseif sCommand == "run" then if res then local func, err = load(res, sCode, "t", _ENV) if not func then - printError( err ) + printError(err) return end local success, msg = pcall(func, select(3, ...)) if not success then - printError( msg ) + printError(msg) end end else diff --git a/src/main/resources/data/computercraft/lua/rom/programs/http/wget.lua b/src/main/resources/data/computercraft/lua/rom/programs/http/wget.lua index e05def30e..dbfa3aeb7 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/http/wget.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/http/wget.lua @@ -1,15 +1,15 @@ local function printUsage() - print( "Usage:" ) - print( "wget [filename]" ) - print( "wget run " ) + print("Usage:") + print("wget [filename]") + print("wget run ") end local tArgs = { ... } local run = false if tArgs[1] == "run" then - table.remove( tArgs, 1 ) + table.remove(tArgs, 1) run = true end @@ -18,36 +18,36 @@ if #tArgs < 1 then return end -local url = table.remove( tArgs, 1 ) +local url = table.remove(tArgs, 1) if not http then - printError( "wget requires http API" ) - printError( "Set http_enable to true in ComputerCraft.cfg" ) + printError("wget requires the http API") + printError("Set http.enabled to true in CC: Tweaked's config") return end -local function getFilename( sUrl ) - sUrl = sUrl:gsub( "[#?].*" , "" ):gsub( "/+$" , "" ) - return sUrl:match( "/([^/]+)$" ) +local function getFilename(sUrl) + sUrl = sUrl:gsub("[#?].*" , ""):gsub("/+$" , "") + return sUrl:match("/([^/]+)$") end -local function get( sUrl ) +local function get(sUrl) -- Check if the URL is valid - local ok, err = http.checkURL( url ) + local ok, err = http.checkURL(url) if not ok then - printError( err or "Invalid URL." ) + printError(err or "Invalid URL.") return end - write( "Connecting to " .. sUrl .. "... " ) + write("Connecting to " .. sUrl .. "... ") - local response = http.get( sUrl , nil , true ) + local response = http.get(sUrl , nil , true) if not response then - print( "Failed." ) + print("Failed.") return nil end - print( "Success." ) + print("Success.") local sResponse = response.readAll() response.close() @@ -66,22 +66,22 @@ if run then local ok, err = pcall(func, table.unpack(tArgs)) if not ok then - printError( err ) + printError(err) end else - local sFile = tArgs[1] or getFilename( url ) - local sPath = shell.resolve( sFile ) - if fs.exists( sPath ) then - print( "File already exists" ) + local sFile = tArgs[1] or getFilename(url) + local sPath = shell.resolve(sFile) + if fs.exists(sPath) then + print("File already exists") return end local res = get(url) if not res then return end - local file = fs.open( sPath, "wb" ) - file.write( res ) + local file = fs.open(sPath, "wb") + file.write(res) file.close() - print( "Downloaded as " .. sFile ) + print("Downloaded as " .. sFile) end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/id.lua b/src/main/resources/data/computercraft/lua/rom/programs/id.lua index 439fc9f3c..dda736612 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/id.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/id.lua @@ -2,28 +2,28 @@ local sDrive = nil local tArgs = { ... } if #tArgs > 0 then - sDrive = tostring( tArgs[1] ) + sDrive = tostring(tArgs[1]) end if sDrive == nil then - print( "This is computer #" .. os.getComputerID() ) + print("This is computer #" .. os.getComputerID()) local label = os.getComputerLabel() if label then - print( "This computer is labelled \"" .. label .. "\"" ) + print("This computer is labelled \"" .. label .. "\"") end else - local bData = disk.hasData( sDrive ) + local bData = disk.hasData(sDrive) if not bData then - print( "No disk in drive " .. sDrive ) + print("No disk in drive " .. sDrive) return end - print( "The disk is #" .. disk.getID( sDrive ) ) + print("The disk is #" .. disk.getID(sDrive)) - local label = disk.getLabel( sDrive ) + local label = disk.getLabel(sDrive) if label then - print( "The disk is labelled \"" .. label .. "\"" ) + print("The disk is labelled \"" .. label .. "\"") end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/label.lua b/src/main/resources/data/computercraft/lua/rom/programs/label.lua index ea23277a9..d0e712a05 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/label.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/label.lua @@ -1,67 +1,67 @@ local function printUsage() - print( "Usages:" ) - print( "label get" ) - print( "label get " ) - print( "label set " ) - print( "label set " ) - print( "label clear" ) - print( "label clear " ) + print("Usages:") + print("label get") + print("label get ") + print("label set ") + print("label set ") + print("label clear") + print("label clear ") end -local function checkDrive( sDrive ) - if peripheral.getType( sDrive ) == "drive" then +local function checkDrive(sDrive) + if peripheral.getType(sDrive) == "drive" then -- Check the disk exists - local bData = disk.hasData( sDrive ) + local bData = disk.hasData(sDrive) if not bData then - print( "No disk in " .. sDrive .. " drive" ) + print("No disk in " .. sDrive .. " drive") return false end else - print( "No disk drive named " .. sDrive ) + print("No disk drive named " .. sDrive) return false end return true end -local function get( sDrive ) +local function get(sDrive) if sDrive ~= nil then - if checkDrive( sDrive ) then - local sLabel = disk.getLabel( sDrive ) + if checkDrive(sDrive) then + local sLabel = disk.getLabel(sDrive) if sLabel then - print( "Disk label is \"" .. sLabel .. "\"" ) + print("Disk label is \"" .. sLabel .. "\"") else - print( "No Disk label" ) + print("No Disk label") end end else local sLabel = os.getComputerLabel() if sLabel then - print( "Computer label is \"" .. sLabel .. "\"" ) + print("Computer label is \"" .. sLabel .. "\"") else - print( "No Computer label" ) + print("No Computer label") end end end -local function set( sDrive, sText ) +local function set(sDrive, sText) if sDrive ~= nil then - if checkDrive( sDrive ) then - disk.setLabel( sDrive, sText ) - local sLabel = disk.getLabel( sDrive ) + if checkDrive(sDrive) then + disk.setLabel(sDrive, sText) + local sLabel = disk.getLabel(sDrive) if sLabel then - print( "Disk label set to \"" .. sLabel .. "\"" ) + print("Disk label set to \"" .. sLabel .. "\"") else - print( "Disk label cleared" ) + print("Disk label cleared") end end else - os.setComputerLabel( sText ) + os.setComputerLabel(sText) local sLabel = os.getComputerLabel() if sLabel then - print( "Computer label set to \"" .. sLabel .. "\"" ) + print("Computer label set to \"" .. sLabel .. "\"") else - print( "Computer label cleared" ) + print("Computer label cleared") end end end @@ -71,27 +71,27 @@ local sCommand = tArgs[1] if sCommand == "get" then -- Get a label if #tArgs == 1 then - get( nil ) + get(nil) elseif #tArgs == 2 then - get( tArgs[2] ) + get(tArgs[2]) else printUsage() end elseif sCommand == "set" then -- Set a label if #tArgs == 2 then - set( nil, tArgs[2] ) + set(nil, tArgs[2]) elseif #tArgs == 3 then - set( tArgs[2], tArgs[3] ) + set(tArgs[2], tArgs[3]) else printUsage() end elseif sCommand == "clear" then -- Clear a label if #tArgs == 1 then - set( nil, nil ) + set(nil, nil) elseif #tArgs == 2 then - set( tArgs[2], nil ) + set(tArgs[2], nil) else printUsage() end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/list.lua b/src/main/resources/data/computercraft/lua/rom/programs/list.lua index f493d8ae5..759130bb6 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/list.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/list.lua @@ -4,35 +4,35 @@ local tArgs = { ... } -- Get all the files in the directory local sDir = shell.dir() if tArgs[1] ~= nil then - sDir = shell.resolve( tArgs[1] ) + sDir = shell.resolve(tArgs[1]) end -if not fs.isDir( sDir ) then - printError( "Not a directory" ) +if not fs.isDir(sDir) then + printError("Not a directory") return end -- Sort into dirs/files, and calculate column count -local tAll = fs.list( sDir ) +local tAll = fs.list(sDir) local tFiles = {} local tDirs = {} -local bShowHidden = settings.get( "list.show_hidden" ) -for _, sItem in pairs( tAll ) do - if bShowHidden or string.sub( sItem, 1, 1 ) ~= "." then - local sPath = fs.combine( sDir, sItem ) - if fs.isDir( sPath ) then - table.insert( tDirs, sItem ) +local bShowHidden = settings.get("list.show_hidden") +for _, sItem in pairs(tAll) do + if bShowHidden or string.sub(sItem, 1, 1) ~= "." then + local sPath = fs.combine(sDir, sItem) + if fs.isDir(sPath) then + table.insert(tDirs, sItem) else - table.insert( tFiles, sItem ) + table.insert(tFiles, sItem) end end end -table.sort( tDirs ) -table.sort( tFiles ) +table.sort(tDirs) +table.sort(tFiles) if term.isColour() then - textutils.pagedTabulate( colors.green, tDirs, colors.white, tFiles ) + textutils.pagedTabulate(colors.green, tDirs, colors.white, tFiles) else - textutils.pagedTabulate( tDirs, tFiles ) + textutils.pagedTabulate(tDirs, tFiles) end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/lua.lua b/src/main/resources/data/computercraft/lua/rom/programs/lua.lua index 63d4c6add..5eea4dd81 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/lua.lua @@ -1,23 +1,25 @@ local tArgs = { ... } if #tArgs > 0 then - print( "This is an interactive Lua prompt." ) - print( "To run a lua program, just type its name." ) + print("This is an interactive Lua prompt.") + print("To run a lua program, just type its name.") return end +local pretty = require "cc.pretty" + local bRunning = true local tCommandHistory = {} local tEnv = { ["exit"] = setmetatable({}, { - __tostring = function() return "Call exit() to exit" end, + __tostring = function() return "Call exit() to exit." end, __call = function() bRunning = false end, }), - ["_echo"] = function( ... ) + ["_echo"] = function(...) return ... end, } -setmetatable( tEnv, { __index = _ENV } ) +setmetatable(tEnv, { __index = _ENV }) -- Replace our package.path, so that it loads from the current directory, rather -- than from /rom/programs. This makes it a little more friendly to use and @@ -37,38 +39,38 @@ do end if term.isColour() then - term.setTextColour( colours.yellow ) + term.setTextColour(colours.yellow) end -print( "Interactive Lua prompt." ) -print( "Call exit() to exit." ) -term.setTextColour( colours.white ) +print("Interactive Lua prompt.") +print("Call exit() to exit.") +term.setTextColour(colours.white) while bRunning do --if term.isColour() then -- term.setTextColour( colours.yellow ) --end - write( "lua> " ) + write("lua> ") --term.setTextColour( colours.white ) - local s = read( nil, tCommandHistory, function( sLine ) - if settings.get( "lua.autocomplete" ) then - local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.:]+$" ) + local s = read(nil, tCommandHistory, function(sLine) + if settings.get("lua.autocomplete") then + local nStartPos = string.find(sLine, "[a-zA-Z0-9_%.:]+$") if nStartPos then - sLine = string.sub( sLine, nStartPos ) + sLine = string.sub(sLine, nStartPos) end if #sLine > 0 then - return textutils.complete( sLine, tEnv ) + return textutils.complete(sLine, tEnv) end end return nil - end ) + end) if s:match("%S") and tCommandHistory[#tCommandHistory] ~= s then - table.insert( tCommandHistory, s ) + table.insert(tCommandHistory, s) end local nForcePrint = 0 - local func, e = load( s, "=lua", "t", tEnv ) - local func2 = load( "return _echo(" .. s .. ");", "=lua", "t", tEnv ) + local func, e = load(s, "=lua", "t", tEnv) + local func2 = load("return _echo(" .. s .. ");", "=lua", "t", tEnv) if not func then if func2 then func = func2 @@ -82,33 +84,24 @@ while bRunning do end if func then - local tResults = table.pack( pcall( func ) ) + local tResults = table.pack(pcall(func)) if tResults[1] then local n = 1 while n < tResults.n or n <= nForcePrint do - local value = tResults[ n + 1 ] - if type( value ) == "table" then - local metatable = getmetatable( value ) - if type(metatable) == "table" and type(metatable.__tostring) == "function" then - print( tostring( value ) ) - else - local ok, serialised = pcall( textutils.serialise, value ) - if ok then - print( serialised ) - else - print( tostring( value ) ) - end - end + local value = tResults[n + 1] + local ok, serialised = pcall(pretty.pretty, value) + if ok then + pretty.print(serialised) else - print( tostring( value ) ) + print(tostring(value)) end n = n + 1 end else - printError( tResults[2] ) + printError(tResults[2]) end else - printError( e ) + printError(e) end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/mkdir.lua b/src/main/resources/data/computercraft/lua/rom/programs/mkdir.lua index 3bdb5e840..bbdd08002 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/mkdir.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/mkdir.lua @@ -1,17 +1,17 @@ local tArgs = { ... } if #tArgs < 1 then - print( "Usage: mkdir " ) + print("Usage: mkdir ") return end -for _, v in ipairs( tArgs ) do - local sNewDir = shell.resolve( v ) - if fs.exists( sNewDir ) and not fs.isDir( sNewDir ) then - printError( v .. ": Destination exists" ) - elseif fs.isReadOnly( sNewDir ) then - printError( v .. ": Access denied" ) +for _, v in ipairs(tArgs) do + local sNewDir = shell.resolve(v) + if fs.exists(sNewDir) and not fs.isDir(sNewDir) then + printError(v .. ": Destination exists") + elseif fs.isReadOnly(sNewDir) then + printError(v .. ": Access denied") else - fs.makeDir( sNewDir ) + fs.makeDir(sNewDir) end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua b/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua index 16afddd29..e6daed9e8 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua @@ -1,5 +1,5 @@ local function printUsage() - print( "Usage: monitor " ) + print("Usage: monitor ") return end @@ -10,56 +10,65 @@ if #tArgs < 2 then end local sName = tArgs[1] -if peripheral.getType( sName ) ~= "monitor" then - print( "No monitor named " .. sName ) +if peripheral.getType(sName) ~= "monitor" then + print("No monitor named " .. sName) return end local sProgram = tArgs[2] -local sPath = shell.resolveProgram( sProgram ) +local sPath = shell.resolveProgram(sProgram) if sPath == nil then - print( "No such program: " .. sProgram ) + print("No such program: " .. sProgram) return end -print( "Running " .. sProgram .. " on monitor " .. sName ) +print("Running " .. sProgram .. " on monitor " .. sName) -local monitor = peripheral.wrap( sName ) -local previousTerm = term.redirect( monitor ) +local monitor = peripheral.wrap(sName) +local previousTerm = term.redirect(monitor) -local co = coroutine.create( function() - shell.run( sProgram, table.unpack( tArgs, 3 ) ) -end ) +local co = coroutine.create(function() + shell.run(sProgram, table.unpack(tArgs, 3)) +end) -local function resume( ... ) - local ok, param = coroutine.resume( co, ... ) +local function resume(...) + local ok, param = coroutine.resume(co, ...) if not ok then - printError( param ) + printError(param) end return param end -local ok, param = pcall( function() +local timers = {} + +local ok, param = pcall(function() local sFilter = resume() - while coroutine.status( co ) ~= "dead" do - local tEvent = table.pack( os.pullEventRaw() ) + while coroutine.status(co) ~= "dead" do + local tEvent = table.pack(os.pullEventRaw()) if sFilter == nil or tEvent[1] == sFilter or tEvent[1] == "terminate" then - sFilter = resume( table.unpack( tEvent, 1, tEvent.n ) ) + sFilter = resume(table.unpack(tEvent, 1, tEvent.n)) end - if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "mouse_click") then + if coroutine.status(co) ~= "dead" and (sFilter == nil or sFilter == "mouse_click") then if tEvent[1] == "monitor_touch" and tEvent[2] == sName then - sFilter = resume( "mouse_click", 1, table.unpack( tEvent, 3, tEvent.n ) ) + timers[os.startTimer(0.1)] = { tEvent[3], tEvent[4] } + sFilter = resume("mouse_click", 1, table.unpack(tEvent, 3, tEvent.n)) end end - if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "term_resize") then + if coroutine.status(co) ~= "dead" and (sFilter == nil or sFilter == "term_resize") then if tEvent[1] == "monitor_resize" and tEvent[2] == sName then - sFilter = resume( "term_resize" ) + sFilter = resume("term_resize") + end + end + if coroutine.status(co) ~= "dead" and (sFilter == nil or sFilter == "mouse_up") then + if tEvent[1] == "timer" and timers[tEvent[2]] then + sFilter = resume("mouse_up", 1, table.unpack(timers[tEvent[2]], 1, 2)) + timers[tEvent[2]] = nil end end end -end ) +end) -term.redirect( previousTerm ) +term.redirect(previousTerm) if not ok then - printError( param ) + printError(param) end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/motd.lua b/src/main/resources/data/computercraft/lua/rom/programs/motd.lua index a7142fb85..c8c75a40b 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/motd.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/motd.lua @@ -1,6 +1,6 @@ local tMotd = {} -for sPath in string.gmatch(settings.get( "motd.path" ), "[^:]+") do +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) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/move.lua b/src/main/resources/data/computercraft/lua/rom/programs/move.lua index 5b2dd6266..0ebc5f7f7 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/move.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/move.lua @@ -1,24 +1,24 @@ local tArgs = { ... } if #tArgs < 2 then - print( "Usage: mv " ) + print("Usage: mv ") return end -local sSource = shell.resolve( tArgs[1] ) -local sDest = shell.resolve( tArgs[2] ) -local tFiles = fs.find( sSource ) +local sSource = shell.resolve(tArgs[1]) +local sDest = shell.resolve(tArgs[2]) +local tFiles = fs.find(sSource) if #tFiles > 0 then - for _, sFile in ipairs( tFiles ) do - if fs.isDir( sDest ) then - fs.move( sFile, fs.combine( sDest, fs.getName(sFile) ) ) + for _, sFile in ipairs(tFiles) do + if fs.isDir(sDest) then + fs.move(sFile, fs.combine(sDest, fs.getName(sFile))) elseif #tFiles == 1 then - fs.move( sFile, sDest ) + fs.move(sFile, sDest) else - printError( "Cannot overwrite file multiple times" ) + printError("Cannot overwrite file multiple times") return end end else - printError( "No matching files" ) + printError("No matching files") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/peripherals.lua b/src/main/resources/data/computercraft/lua/rom/programs/peripherals.lua index 33b7e9c9a..290619614 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/peripherals.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/peripherals.lua @@ -1,10 +1,10 @@ local tPeripherals = peripheral.getNames() -print( "Attached Peripherals:" ) +print("Attached Peripherals:") if #tPeripherals > 0 then for n = 1, #tPeripherals do local sPeripheral = tPeripherals[n] - print( sPeripheral .. " (" .. peripheral.getType( sPeripheral ) .. ")" ) + print(sPeripheral .. " (" .. peripheral.getType(sPeripheral) .. ")") end else - print( "None" ) + print("None") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/pocket/equip.lua b/src/main/resources/data/computercraft/lua/rom/programs/pocket/equip.lua index 62aa7c98d..b4fdb399a 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/pocket/equip.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/pocket/equip.lua @@ -1,11 +1,11 @@ if not pocket then - printError( "Requires a Pocket Computer" ) + printError("Requires a Pocket Computer") return end local ok, err = pocket.equipBack() if not ok then - printError( err ) + printError(err) else - print( "Item equipped" ) + print("Item equipped") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/pocket/falling.lua b/src/main/resources/data/computercraft/lua/rom/programs/pocket/falling.lua index bdc922e4f..deb01c380 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/pocket/falling.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/pocket/falling.lua @@ -158,9 +158,9 @@ local block_T = { bg = colorass(colors.purple, colors.white), } -local blocks = { block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T} +local blocks = { block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T } -local points = {4, 10, 30, 120} +local points = { 4, 10, 30, 120 } local function lpad(text, amt) text = tostring(text) @@ -456,7 +456,7 @@ local function playGame() sleep(.25) for r = 1, #rows do table.remove(pit, rows[r]) - table.insert(pit, 1, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + table.insert(pit, 1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }) end redrawPit() lines = lines + #rows @@ -496,7 +496,7 @@ local function playGame() while not halt do - local e = {os.pullEvent()} + local e = { os.pullEvent() } if e[1] == "timer" then if e[2] == dropTimer then blockFall() @@ -517,7 +517,7 @@ local function playGame() elseif key == keys.space then hidePit() msgBox("Paused") - while ({os.pullEvent("key")})[2] ~= keys.space do end + while ({ os.pullEvent("key") })[2] ~= keys.space do end redrawPit() drawBlockAt(curBlock, curX, curY, curRot) dropTimer = os.startTimer(dropSpeed) @@ -606,7 +606,7 @@ local function runMenu() drawMenu() while true do - local event = {os.pullEvent()} + local event = { os.pullEvent() } if event[1] == "key" then local key = event[2] if key == keys.right or key == keys.d and selected == 1 then diff --git a/src/main/resources/data/computercraft/lua/rom/programs/pocket/unequip.lua b/src/main/resources/data/computercraft/lua/rom/programs/pocket/unequip.lua index 28308d407..8cd1ef444 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/pocket/unequip.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/pocket/unequip.lua @@ -1,11 +1,11 @@ if not pocket then - printError( "Requires a Pocket Computer" ) + printError("Requires a Pocket Computer") return end local ok, err = pocket.unequipBack() if not ok then - printError( err ) + printError(err) else - print( "Item unequipped" ) + print("Item unequipped") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/programs.lua b/src/main/resources/data/computercraft/lua/rom/programs/programs.lua index 1fe382799..015264d94 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/programs.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/programs.lua @@ -5,5 +5,5 @@ if #tArgs > 0 and tArgs[1] == "all" then bAll = true end -local tPrograms = shell.programs( bAll ) -textutils.pagedTabulate( tPrograms ) +local tPrograms = shell.programs(bAll) +textutils.pagedTabulate(tPrograms) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/reboot.lua b/src/main/resources/data/computercraft/lua/rom/programs/reboot.lua index 2ea87bb2e..2824cc0c6 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/reboot.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/reboot.lua @@ -1,8 +1,8 @@ if term.isColour() then - term.setTextColour( colours.yellow ) + term.setTextColour(colours.yellow) end -print( "Goodbye" ) -term.setTextColour( colours.white ) +print("Goodbye") +term.setTextColour(colours.white) -sleep( 1 ) +sleep(1) os.reboot() diff --git a/src/main/resources/data/computercraft/lua/rom/programs/rednet/chat.lua b/src/main/resources/data/computercraft/lua/rom/programs/rednet/chat.lua index 58a513f36..c632104b1 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/rednet/chat.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/rednet/chat.lua @@ -2,29 +2,29 @@ local tArgs = { ... } local function printUsage() - print( "Usages:" ) - print( "chat host " ) - print( "chat join " ) + print("Usages:") + print("chat host ") + print("chat join ") end local sOpenedModem = nil local function openModem() - for _, sModem in ipairs( peripheral.getNames() ) do - if peripheral.getType( sModem ) == "modem" then - if not rednet.isOpen( sModem ) then - rednet.open( sModem ) + for _, sModem in ipairs(peripheral.getNames()) do + if peripheral.getType(sModem) == "modem" then + if not rednet.isOpen(sModem) then + rednet.open(sModem) sOpenedModem = sModem end return true end end - print( "No modems found." ) + print("No modems found.") return false end local function closeModem() if sOpenedModem ~= nil then - rednet.close( sOpenedModem ) + rednet.close(sOpenedModem) sOpenedModem = nil end end @@ -53,73 +53,73 @@ if sCommand == "host" then if not openModem() then return end - rednet.host( "chat", sHostname ) - print( "0 users connected." ) + rednet.host("chat", sHostname) + print("0 users connected.") local tUsers = {} local nUsers = 0 - local function send( sText, nUserID ) + local function send(sText, nUserID) if nUserID then - local tUser = tUsers[ nUserID ] + local tUser = tUsers[nUserID] if tUser then - rednet.send( tUser.nID, { + rednet.send(tUser.nID, { sType = "text", nUserID = nUserID, sText = sText, - }, "chat" ) + }, "chat") end else - for nUserID, tUser in pairs( tUsers ) do - rednet.send( tUser.nID, { + for nUserID, tUser in pairs(tUsers) do + rednet.send(tUser.nID, { sType = "text", nUserID = nUserID, sText = sText, - }, "chat" ) + }, "chat") end end end -- Setup ping pong local tPingPongTimer = {} - local function ping( nUserID ) - local tUser = tUsers[ nUserID ] - rednet.send( tUser.nID, { + local function ping(nUserID) + local tUser = tUsers[nUserID] + rednet.send(tUser.nID, { sType = "ping to client", nUserID = nUserID, - }, "chat" ) + }, "chat") - local timer = os.startTimer( 15 ) + local timer = os.startTimer(15) tUser.bPingPonged = false - tPingPongTimer[ timer ] = nUserID + tPingPongTimer[timer] = nUserID end local function printUsers() local _, y = term.getCursorPos() - term.setCursorPos( 1, y - 1 ) + term.setCursorPos(1, y - 1) term.clearLine() if nUsers == 1 then - print( nUsers .. " user connected." ) + print(nUsers .. " user connected.") else - print( nUsers .. " users connected." ) + print(nUsers .. " users connected.") end end -- Handle messages - local ok, error = pcall( function() - parallel.waitForAny( function() + local ok, error = pcall(parallel.waitForAny, + function() while true do - local _, timer = os.pullEvent( "timer" ) - local nUserID = tPingPongTimer[ timer ] - if nUserID and tUsers[ nUserID ] then - local tUser = tUsers[ nUserID ] + local _, timer = os.pullEvent("timer") + local nUserID = tPingPongTimer[timer] + if nUserID and tUsers[nUserID] then + local tUser = tUsers[nUserID] if tUser then if not tUser.bPingPonged then - send( "* " .. tUser.sUsername .. " has timed out" ) - tUsers[ nUserID ] = nil + send("* " .. tUser.sUsername .. " has timed out") + tUsers[nUserID] = nil nUsers = nUsers - 1 printUsers() else - ping( nUserID ) + ping(nUserID) end end end @@ -129,91 +129,91 @@ if sCommand == "host" then while true do local tCommands tCommands = { - ["me"] = function( tUser, sContent ) + ["me"] = function(tUser, sContent) if #sContent > 0 then - send( "* " .. tUser.sUsername .. " " .. sContent ) + send("* " .. tUser.sUsername .. " " .. sContent) else - send( "* Usage: /me [words]", tUser.nUserID ) + send("* Usage: /me [words]", tUser.nUserID) end end, - ["nick"] = function( tUser, sContent ) + ["nick"] = function(tUser, sContent) if #sContent > 0 then local sOldName = tUser.sUsername tUser.sUsername = sContent - send( "* " .. sOldName .. " is now known as " .. tUser.sUsername ) + send("* " .. sOldName .. " is now known as " .. tUser.sUsername) else - send( "* Usage: /nick [nickname]", tUser.nUserID ) + send("* Usage: /nick [nickname]", tUser.nUserID) end end, - ["users"] = function( tUser, sContent ) - send( "* Connected Users:", tUser.nUserID ) + ["users"] = function(tUser, sContent) + send("* Connected Users:", tUser.nUserID) local sUsers = "*" - for _, tUser in pairs( tUsers ) do + for _, tUser in pairs(tUsers) do sUsers = sUsers .. " " .. tUser.sUsername end - send( sUsers, tUser.nUserID ) + send(sUsers, tUser.nUserID) end, - ["help"] = function( tUser, sContent ) - send( "* Available commands:", tUser.nUserID ) + ["help"] = function(tUser, sContent) + send("* Available commands:", tUser.nUserID) local sCommands = "*" - for sCommand in pairs( tCommands ) do + for sCommand in pairs(tCommands) do sCommands = sCommands .. " /" .. sCommand end - send( sCommands .. " /logout", tUser.nUserID ) + send(sCommands .. " /logout", tUser.nUserID) end, } - local nSenderID, tMessage = rednet.receive( "chat" ) - if type( tMessage ) == "table" then + local nSenderID, tMessage = rednet.receive("chat") + if type(tMessage) == "table" then if tMessage.sType == "login" then -- Login from new client local nUserID = tMessage.nUserID local sUsername = tMessage.sUsername if nUserID and sUsername then - tUsers[ nUserID ] = { + tUsers[nUserID] = { nID = nSenderID, nUserID = nUserID, sUsername = sUsername, } nUsers = nUsers + 1 printUsers() - send( "* " .. sUsername .. " has joined the chat" ) - ping( nUserID ) + send("* " .. sUsername .. " has joined the chat") + ping(nUserID) end else -- Something else from existing client local nUserID = tMessage.nUserID - local tUser = tUsers[ nUserID ] + local tUser = tUsers[nUserID] if tUser and tUser.nID == nSenderID then if tMessage.sType == "logout" then - send( "* " .. tUser.sUsername .. " has left the chat" ) - tUsers[ nUserID ] = nil + send("* " .. tUser.sUsername .. " has left the chat") + tUsers[nUserID] = nil nUsers = nUsers - 1 printUsers() elseif tMessage.sType == "chat" then local sMessage = tMessage.sText if sMessage then - local sCommand = string.match( sMessage, "^/([a-z]+)" ) + local sCommand = string.match(sMessage, "^/([a-z]+)") if sCommand then - local fnCommand = tCommands[ sCommand ] + local fnCommand = tCommands[sCommand] if fnCommand then - local sContent = string.sub( sMessage, #sCommand + 3 ) - fnCommand( tUser, sContent ) + local sContent = string.sub(sMessage, #sCommand + 3) + fnCommand(tUser, sContent) else - send( "* Unrecognised command: /" .. sCommand, tUser.nUserID ) + send("* Unrecognised command: /" .. sCommand, tUser.nUserID) end else - send( "<" .. tUser.sUsername .. "> " .. tMessage.sText ) + send("<" .. tUser.sUsername .. "> " .. tMessage.sText) end end elseif tMessage.sType == "ping to server" then - rednet.send( tUser.nID, { + rednet.send(tUser.nID, { sType = "pong to client", nUserID = nUserID, - }, "chat" ) + }, "chat") elseif tMessage.sType == "pong to server" then tUser.bPingPonged = true @@ -223,20 +223,20 @@ if sCommand == "host" then end end end - end ) - end ) + end + ) if not ok then - printError( error ) + printError(error) end -- Unhost server - for nUserID, tUser in pairs( tUsers ) do - rednet.send( tUser.nID, { + for nUserID, tUser in pairs(tUsers) do + rednet.send(tUser.nID, { sType = "kick", nUserID = nUserID, - }, "chat" ) + }, "chat") end - rednet.unhost( "chat" ) + rednet.unhost("chat") closeModem() elseif sCommand == "join" then @@ -253,93 +253,93 @@ elseif sCommand == "join" then if not openModem() then return end - write( "Looking up " .. sHostname .. "... " ) - local nHostID = rednet.lookup( "chat", sHostname ) + write("Looking up " .. sHostname .. "... ") + local nHostID = rednet.lookup("chat", sHostname) if nHostID == nil then - print( "Failed." ) + print("Failed.") return else - print( "Success." ) + print("Success.") end -- Login - local nUserID = math.random( 1, 2147483647 ) - rednet.send( nHostID, { + local nUserID = math.random(1, 2147483647) + rednet.send(nHostID, { sType = "login", nUserID = nUserID, sUsername = sUsername, - }, "chat" ) + }, "chat") -- Setup ping pong local bPingPonged = true - local pingPongTimer = os.startTimer( 0 ) + local pingPongTimer = os.startTimer(0) local function ping() - rednet.send( nHostID, { + rednet.send(nHostID, { sType = "ping to server", nUserID = nUserID, - }, "chat" ) + }, "chat") bPingPonged = false - pingPongTimer = os.startTimer( 15 ) + pingPongTimer = os.startTimer(15) end -- Handle messages local w, h = term.getSize() local parentTerm = term.current() - local titleWindow = window.create( parentTerm, 1, 1, w, 1, true ) - local historyWindow = window.create( parentTerm, 1, 2, w, h - 2, true ) - local promptWindow = window.create( parentTerm, 1, h, w, 1, true ) - historyWindow.setCursorPos( 1, h - 2 ) + local titleWindow = window.create(parentTerm, 1, 1, w, 1, true) + local historyWindow = window.create(parentTerm, 1, 2, w, h - 2, true) + local promptWindow = window.create(parentTerm, 1, h, w, 1, true) + historyWindow.setCursorPos(1, h - 2) term.clear() - term.setTextColour( textColour ) - term.redirect( promptWindow ) + term.setTextColour(textColour) + term.redirect(promptWindow) promptWindow.restoreCursor() local function drawTitle() local w = titleWindow.getSize() local sTitle = sUsername .. " on " .. sHostname - titleWindow.setTextColour( highlightColour ) - titleWindow.setCursorPos( math.floor( w / 2 - #sTitle / 2 ), 1 ) + titleWindow.setTextColour(highlightColour) + titleWindow.setCursorPos(math.floor(w / 2 - #sTitle / 2), 1) titleWindow.clearLine() - titleWindow.write( sTitle ) + titleWindow.write(sTitle) promptWindow.restoreCursor() end - local function printMessage( sMessage ) - term.redirect( historyWindow ) + local function printMessage(sMessage) + term.redirect(historyWindow) print() - if string.match( sMessage, "^%*" ) then + if string.match(sMessage, "^%*") then -- Information - term.setTextColour( highlightColour ) - write( sMessage ) - term.setTextColour( textColour ) + term.setTextColour(highlightColour) + write(sMessage) + term.setTextColour(textColour) else -- Chat - local sUsernameBit = string.match( sMessage, "^<[^>]*>" ) + local sUsernameBit = string.match(sMessage, "^<[^>]*>") if sUsernameBit then - term.setTextColour( highlightColour ) - write( sUsernameBit ) - term.setTextColour( textColour ) - write( string.sub( sMessage, #sUsernameBit + 1 ) ) + term.setTextColour(highlightColour) + write(sUsernameBit) + term.setTextColour(textColour) + write(string.sub(sMessage, #sUsernameBit + 1)) else - write( sMessage ) + write(sMessage) end end - term.redirect( promptWindow ) + term.redirect(promptWindow) promptWindow.restoreCursor() end drawTitle() - local ok, error = pcall( function() - parallel.waitForAny( function() + local ok, error = pcall(parallel.waitForAny, + function() while true do local sEvent, timer = os.pullEvent() if sEvent == "timer" then if timer == pingPongTimer then if not bPingPonged then - printMessage( "Server timeout." ) + printMessage("Server timeout.") return else ping() @@ -348,28 +348,28 @@ elseif sCommand == "join" then elseif sEvent == "term_resize" then local w, h = parentTerm.getSize() - titleWindow.reposition( 1, 1, w, 1 ) - historyWindow.reposition( 1, 2, w, h - 2 ) - promptWindow.reposition( 1, h, w, 1 ) + titleWindow.reposition(1, 1, w, 1) + historyWindow.reposition(1, 2, w, h - 2) + promptWindow.reposition(1, h, w, 1) end end end, function() while true do - local nSenderID, tMessage = rednet.receive( "chat" ) - if nSenderID == nHostID and type( tMessage ) == "table" and tMessage.nUserID == nUserID then + local nSenderID, tMessage = rednet.receive("chat") + if nSenderID == nHostID and type(tMessage) == "table" and tMessage.nUserID == nUserID then if tMessage.sType == "text" then local sText = tMessage.sText if sText then - printMessage( sText ) + printMessage(sText) end elseif tMessage.sType == "ping to client" then - rednet.send( nSenderID, { + rednet.send(nSenderID, { sType = "pong to server", nUserID = nUserID, - }, "chat" ) + }, "chat") elseif tMessage.sType == "pong to client" then bPingPonged = true @@ -384,48 +384,48 @@ elseif sCommand == "join" then function() local tSendHistory = {} while true do - promptWindow.setCursorPos( 1, 1 ) + promptWindow.setCursorPos(1, 1) promptWindow.clearLine() - promptWindow.setTextColor( highlightColour ) - promptWindow.write( ": ") - promptWindow.setTextColor( textColour ) + promptWindow.setTextColor(highlightColour) + promptWindow.write(": ") + promptWindow.setTextColor(textColour) - local sChat = read( nil, tSendHistory ) - if string.match( sChat, "^/logout" ) then + local sChat = read(nil, tSendHistory) + if string.match(sChat, "^/logout") then break else - rednet.send( nHostID, { + rednet.send(nHostID, { sType = "chat", nUserID = nUserID, sText = sChat, - }, "chat" ) - table.insert( tSendHistory, sChat ) + }, "chat") + table.insert(tSendHistory, sChat) end end - end ) - end ) + end + ) -- Close the windows - term.redirect( parentTerm ) + term.redirect(parentTerm) -- Print error notice local _, h = term.getSize() - term.setCursorPos( 1, h ) + term.setCursorPos(1, h) term.clearLine() - term.setCursorBlink( false ) + term.setCursorBlink(false) if not ok then - printError( error ) + printError(error) end -- Logout - rednet.send( nHostID, { + rednet.send(nHostID, { sType = "logout", nUserID = nUserID, - }, "chat" ) + }, "chat") closeModem() -- Print disconnection notice - print( "Disconnected." ) + print("Disconnected.") else -- "chat somethingelse" diff --git a/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua b/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua index c6bad5634..b9a9bcb94 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua @@ -1,40 +1,40 @@ -- Find modems local tModems = {} -for _, sModem in ipairs( peripheral.getNames() ) do - if peripheral.getType( sModem ) == "modem" then - table.insert( tModems, sModem ) +for _, sModem in ipairs(peripheral.getNames()) do + if peripheral.getType(sModem) == "modem" then + table.insert(tModems, sModem) end end if #tModems == 0 then - print( "No modems found." ) + print("No modems found.") return elseif #tModems == 1 then - print( "1 modem found." ) + print("1 modem found.") else - print( #tModems .. " modems found." ) + print(#tModems .. " modems found.") end -local function open( nChannel ) +local function open(nChannel) for n = 1, #tModems do local sModem = tModems[n] - peripheral.call( sModem, "open", nChannel ) + peripheral.call(sModem, "open", nChannel) end end -local function close( nChannel ) +local function close(nChannel) for n = 1, #tModems do local sModem = tModems[n] - peripheral.call( sModem, "close", nChannel ) + peripheral.call(sModem, "close", nChannel) end end -- Open channels -print( "0 messages repeated." ) -open( rednet.CHANNEL_REPEAT ) +print("0 messages repeated.") +open(rednet.CHANNEL_REPEAT) -- Main loop (terminate to break) -local ok, error = pcall( function() +local ok, error = pcall(function() local tReceivedMessages = {} local tReceivedMessageTimeouts = {} local nTransmittedMessages = 0 @@ -44,28 +44,28 @@ local ok, error = pcall( function() if sEvent == "modem_message" then -- Got a modem message, rebroadcast it if it's a rednet thing if nChannel == rednet.CHANNEL_REPEAT then - if type( tMessage ) == "table" and tMessage.nMessageID and tMessage.nRecipient and type(tMessage.nRecipient) == "number" then - if not tReceivedMessages[ tMessage.nMessageID ] then + if type(tMessage) == "table" and tMessage.nMessageID and tMessage.nRecipient and type(tMessage.nRecipient) == "number" then + if not tReceivedMessages[tMessage.nMessageID] then -- Ensure we only repeat a message once - tReceivedMessages[ tMessage.nMessageID ] = true - tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID + tReceivedMessages[tMessage.nMessageID] = true + tReceivedMessageTimeouts[os.startTimer(30)] = tMessage.nMessageID -- Send on all other open modems, to the target and to other repeaters for n = 1, #tModems do local sOtherModem = tModems[n] - peripheral.call( sOtherModem, "transmit", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage ) - peripheral.call( sOtherModem, "transmit", tMessage.nRecipient, nReplyChannel, tMessage ) + peripheral.call(sOtherModem, "transmit", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage) + peripheral.call(sOtherModem, "transmit", tMessage.nRecipient, nReplyChannel, tMessage) end -- Log the event nTransmittedMessages = nTransmittedMessages + 1 local _, y = term.getCursorPos() - term.setCursorPos( 1, y - 1 ) + term.setCursorPos(1, y - 1) term.clearLine() if nTransmittedMessages == 1 then - print( nTransmittedMessages .. " message repeated." ) + print(nTransmittedMessages .. " message repeated.") else - print( nTransmittedMessages .. " messages repeated." ) + print(nTransmittedMessages .. " messages repeated.") end end end @@ -74,18 +74,18 @@ local ok, error = pcall( function() elseif sEvent == "timer" then -- Got a timer event, use it to clear the message history local nTimer = sModem - local nMessageID = tReceivedMessageTimeouts[ nTimer ] + local nMessageID = tReceivedMessageTimeouts[nTimer] if nMessageID then - tReceivedMessageTimeouts[ nTimer ] = nil - tReceivedMessages[ nMessageID ] = nil + tReceivedMessageTimeouts[nTimer] = nil + tReceivedMessages[nMessageID] = nil end end end -end ) +end) if not ok then - printError( error ) + printError(error) end -- Close channels -close( rednet.CHANNEL_REPEAT ) +close(rednet.CHANNEL_REPEAT) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/redstone.lua b/src/main/resources/data/computercraft/lua/rom/programs/redstone.lua index ff7f87a48..35fae9f04 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/redstone.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/redstone.lua @@ -2,64 +2,64 @@ local tArgs = { ... } local function printUsage() - print( "Usages:" ) - print( "redstone probe" ) - print( "redstone set " ) - print( "redstone set " ) - print( "redstone pulse " ) + print("Usages:") + print("redstone probe") + print("redstone set ") + print("redstone set ") + print("redstone pulse ") end local sCommand = tArgs[1] if sCommand == "probe" then -- "redstone probe" -- Regular input - print( "Redstone inputs: " ) + print("Redstone inputs: ") local count = 0 local bundledCount = 0 - for _, sSide in ipairs( redstone.getSides() ) do - if redstone.getBundledInput( sSide ) > 0 then + for _, sSide in ipairs(redstone.getSides()) do + if redstone.getBundledInput(sSide) > 0 then bundledCount = bundledCount + 1 end - if redstone.getInput( sSide ) then + if redstone.getInput(sSide) then if count > 0 then - io.write( ", " ) + io.write(", ") end - io.write( sSide ) + io.write(sSide) count = count + 1 end end if count > 0 then - print( "." ) + print(".") else - print( "None." ) + print("None.") end -- Bundled input if bundledCount > 0 then print() - print( "Bundled inputs:" ) - for _, sSide in ipairs( redstone.getSides() ) do - local nInput = redstone.getBundledInput( sSide ) + print("Bundled inputs:") + for _, sSide in ipairs(redstone.getSides()) do + local nInput = redstone.getBundledInput(sSide) if nInput ~= 0 then - write( sSide .. ": " ) + write(sSide .. ": ") local count = 0 - for sColour, nColour in pairs( colors ) do - if type( nColour ) == "number" and colors.test( nInput, nColour ) then + for sColour, nColour in pairs(colors) do + if type(nColour) == "number" and colors.test(nInput, nColour) then if count > 0 then - write( ", " ) + write(", ") end if term.isColour() then - term.setTextColour( nColour ) + term.setTextColour(nColour) end - write( sColour ) + write(sColour) if term.isColour() then - term.setTextColour( colours.white ) + term.setTextColour(colours.white) end count = count + 1 end end - print( "." ) + print(".") end end end @@ -67,13 +67,13 @@ if sCommand == "probe" then elseif sCommand == "pulse" then -- "redstone pulse" local sSide = tArgs[2] - local nCount = tonumber( tArgs[3] ) or 1 - local nPeriod = tonumber( tArgs[4] ) or 0.5 + local nCount = tonumber(tArgs[3]) or 1 + local nPeriod = tonumber(tArgs[4]) or 0.5 for _ = 1, nCount do - redstone.setOutput( sSide, true ) - sleep( nPeriod / 2 ) - redstone.setOutput( sSide, false ) - sleep( nPeriod / 2 ) + redstone.setOutput(sSide, true) + sleep(nPeriod / 2) + redstone.setOutput(sSide, false) + sleep(nPeriod / 2) end elseif sCommand == "set" then @@ -84,30 +84,30 @@ elseif sCommand == "set" then local sColour = tArgs[3] local nColour = colors[sColour] or colours[sColour] if type(nColour) ~= "number" then - printError( "No such color" ) + printError("No such color") return end local sValue = tArgs[4] if sValue == "true" then - rs.setBundledOutput( sSide, colors.combine( rs.getBundledOutput( sSide ), nColour ) ) + rs.setBundledOutput(sSide, colors.combine(rs.getBundledOutput(sSide), nColour)) elseif sValue == "false" then - rs.setBundledOutput( sSide, colors.subtract( rs.getBundledOutput( sSide ), nColour ) ) + rs.setBundledOutput(sSide, colors.subtract(rs.getBundledOutput(sSide), nColour)) else - print( "Value must be boolean" ) + print("Value must be boolean") end else -- Regular output local sValue = tArgs[3] local nValue = tonumber(sValue) if sValue == "true" then - rs.setOutput( sSide, true ) + rs.setOutput(sSide, true) elseif sValue == "false" then - rs.setOutput( sSide, false ) + rs.setOutput(sSide, false) elseif nValue and nValue >= 0 and nValue <= 15 then - rs.setAnalogOutput( sSide, nValue ) + rs.setAnalogOutput(sSide, nValue) else - print( "Value must be boolean or 0-15" ) + print("Value must be boolean or 0-15") end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/rename.lua b/src/main/resources/data/computercraft/lua/rom/programs/rename.lua index 4583adf62..a90c1f8ad 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/rename.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/rename.lua @@ -1,21 +1,21 @@ local tArgs = { ... } if #tArgs < 2 then - print( "Usage: rename " ) + print("Usage: rename ") return end -local sSource = shell.resolve( tArgs[1] ) -local sDest = shell.resolve( tArgs[2] ) +local sSource = shell.resolve(tArgs[1]) +local sDest = shell.resolve(tArgs[2]) -if not fs.exists( sSource ) then - printError( "No matching files" ) +if not fs.exists(sSource) then + printError("No matching files") return -elseif fs.exists( sDest ) then - printError( "Destination exists" ) +elseif fs.exists(sDest) then + printError("Destination exists") return -elseif fs.isReadOnly( sDest ) then - printError( "Destination is read-only" ) +elseif fs.isReadOnly(sDest) then + printError("Destination is read-only") return end -fs.move( sSource, sDest ) +fs.move(sSource, sDest) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/set.lua b/src/main/resources/data/computercraft/lua/rom/programs/set.lua index f2bacabcc..01d4b246e 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/set.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/set.lua @@ -1,10 +1,11 @@ +local pp = require "cc.pretty" local tArgs = { ... } if #tArgs == 0 then -- "set" local _, y = term.getCursorPos() local tSettings = {} - for n, sName in ipairs( settings.getNames() ) do + for n, sName in ipairs(settings.getNames()) do tSettings[n] = textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName)) end textutils.pagedPrint(table.concat(tSettings, "\n"), y - 3) @@ -12,7 +13,13 @@ if #tArgs == 0 then elseif #tArgs == 1 then -- "set foo" local sName = tArgs[1] - print( textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName)) ) + local deets = settings.getDetails(sName) + local msg = pp.text(sName, colors.cyan) .. " is " .. pp.pretty(deets.value) + if deets.default ~= nil and deets.value ~= deets.default then + msg = msg .. " (default is " .. pp.pretty(deets.default) .. ")" + end + pp.print(msg) + if deets.description then print(deets.description) end else -- "set foo bar" @@ -31,15 +38,18 @@ else value = sValue end - local oldValue = settings.get( sValue ) - if value ~= nil then - settings.set( sName, value ) - print( textutils.serialize(sName) .. " set to " .. textutils.serialize(value) ) + local option = settings.getDetails(sName) + if value == nil then + settings.unset(sName) + print(textutils.serialize(sName) .. " unset") + elseif option.type and option.type ~= type(value) then + printError(("%s is not a valid %s."):format(textutils.serialize(sValue), option.type)) else - settings.unset( sName ) - print( textutils.serialize(sName) .. " unset" ) + settings.set(sName, value) + print(textutils.serialize(sName) .. " set to " .. textutils.serialize(value)) end - if value ~= oldValue then - settings.save( ".settings" ) + + if value ~= option.value then + settings.save() end end 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 5628f0c6f..0d4b9f337 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/shell.lua @@ -5,7 +5,7 @@ local parentShell = shell local parentTerm = term.current() if multishell then - multishell.setTitle( multishell.getCurrent(), "shell" ) + multishell.setTitle(multishell.getCurrent(), "shell") end local bExit = false @@ -16,10 +16,10 @@ local tCompletionInfo = parentShell and parentShell.getCompletionInfo() or {} local tProgramStack = {} local shell = {} -local function createShellEnv( sDir ) +local function createShellEnv(sDir) local tEnv = {} - tEnv[ "shell" ] = shell - tEnv[ "multishell" ] = multishell + tEnv.shell = shell + tEnv.multishell = multishell local package = {} package.loaded = { @@ -40,14 +40,14 @@ local function createShellEnv( sDir ) package.config = "/\n;\n?\n!\n-" package.preload = {} package.loaders = { - function( name ) + function(name) if package.preload[name] then return package.preload[name] else return nil, "no field package.preload['" .. name .. "']" end end, - function( name ) + function(name) local fname = string.gsub(name, "%.", "/") local sError = "" for pattern in string.gmatch(package.path, "[^;]+") do @@ -56,7 +56,7 @@ local function createShellEnv( sDir ) sPath = fs.combine(sDir, sPath) end if fs.exists(sPath) and not fs.isDir(sPath) then - local fnFile, sError = loadfile( sPath, nil, tEnv ) + local fnFile, sError = loadfile(sPath, nil, tEnv) if fnFile then return fnFile, sPath else @@ -74,7 +74,7 @@ local function createShellEnv( sDir ) } local sentinel = {} - local function require( name ) + local function require(name) expect(1, name, "string") if package.loaded[name] == sentinel then error("loop or previous error loading module '" .. name .. "'", 0) @@ -100,8 +100,8 @@ local function createShellEnv( sDir ) error(sError, 2) end - tEnv["package"] = package - tEnv["require"] = require + tEnv.package = package + tEnv.require = require return tEnv end @@ -118,52 +118,52 @@ else bgColour = colours.black end -local function run( _sCommand, ... ) - local sPath = shell.resolveProgram( _sCommand ) +local function run(_sCommand, ...) + local sPath = shell.resolveProgram(_sCommand) if sPath ~= nil then tProgramStack[#tProgramStack + 1] = sPath if multishell then - local sTitle = fs.getName( sPath ) + local sTitle = fs.getName(sPath) if sTitle:sub(-4) == ".lua" then sTitle = sTitle:sub(1, -5) end - multishell.setTitle( multishell.getCurrent(), sTitle ) + multishell.setTitle(multishell.getCurrent(), sTitle) end - local sDir = fs.getDir( sPath ) - local env = createShellEnv( sDir ) - env[ "arg" ] = { [0] = _sCommand, ... } - local result = os.run( env, sPath, ... ) + local sDir = fs.getDir(sPath) + local env = createShellEnv(sDir) + env.arg = { [0] = _sCommand, ... } + local result = os.run(env, sPath, ...) tProgramStack[#tProgramStack] = nil if multishell then if #tProgramStack > 0 then - local sTitle = fs.getName( tProgramStack[#tProgramStack] ) + local sTitle = fs.getName(tProgramStack[#tProgramStack]) if sTitle:sub(-4) == ".lua" then sTitle = sTitle:sub(1, -5) end - multishell.setTitle( multishell.getCurrent(), sTitle ) + multishell.setTitle(multishell.getCurrent(), sTitle) else - multishell.setTitle( multishell.getCurrent(), "shell" ) + multishell.setTitle(multishell.getCurrent(), "shell") end end return result else - printError( "No such program" ) + printError("No such program") return false end end -local function tokenise( ... ) - local sLine = table.concat( { ... }, " " ) +local function tokenise(...) + local sLine = table.concat({ ... }, " ") local tWords = {} local bQuoted = false - for match in string.gmatch( sLine .. "\"", "(.-)\"" ) do + for match in string.gmatch(sLine .. "\"", "(.-)\"") do if bQuoted then - table.insert( tWords, match ) + table.insert(tWords, match) else - for m in string.gmatch( match, "[^ \t]+" ) do - table.insert( tWords, m ) + for m in string.gmatch(match, "[^ \t]+") do + table.insert(tWords, m) end end bQuoted = not bQuoted @@ -172,11 +172,11 @@ local function tokenise( ... ) end -- Install shell API -function shell.run( ... ) - local tWords = tokenise( ... ) +function shell.run(...) + local tWords = tokenise(...) local sCommand = tWords[1] if sCommand then - return run( sCommand, table.unpack( tWords, 2 ) ) + return run(sCommand, table.unpack(tWords, 2)) end return false end @@ -189,58 +189,58 @@ function shell.dir() return sDir end -function shell.setDir( _sDir ) +function shell.setDir(_sDir) expect(1, _sDir, "string") - if not fs.isDir( _sDir ) then - error( "Not a directory", 2 ) + if not fs.isDir(_sDir) then + error("Not a directory", 2) end - sDir = _sDir + sDir = fs.combine(_sDir, "") end function shell.path() return sPath end -function shell.setPath( _sPath ) +function shell.setPath(_sPath) expect(1, _sPath, "string") sPath = _sPath end -function shell.resolve( _sPath ) +function shell.resolve(_sPath) expect(1, _sPath, "string") - local sStartChar = string.sub( _sPath, 1, 1 ) + local sStartChar = string.sub(_sPath, 1, 1) if sStartChar == "/" or sStartChar == "\\" then - return fs.combine( "", _sPath ) + return fs.combine("", _sPath) else - return fs.combine( sDir, _sPath ) + return fs.combine(sDir, _sPath) end end -local function pathWithExtension( _sPath, _sExt ) +local function pathWithExtension(_sPath, _sExt) local nLen = #sPath - local sEndChar = string.sub( _sPath, nLen, nLen ) + local sEndChar = string.sub(_sPath, nLen, nLen) -- Remove any trailing slashes so we can add an extension to the path safely if sEndChar == "/" or sEndChar == "\\" then - _sPath = string.sub( _sPath, 1, nLen - 1 ) + _sPath = string.sub(_sPath, 1, nLen - 1) end return _sPath .. "." .. _sExt end -function shell.resolveProgram( _sCommand ) +function shell.resolveProgram(_sCommand) expect(1, _sCommand, "string") -- Substitute aliases firsts - if tAliases[ _sCommand ] ~= nil then - _sCommand = tAliases[ _sCommand ] + if tAliases[_sCommand] ~= nil then + _sCommand = tAliases[_sCommand] end -- If the path is a global path, use it directly if _sCommand:find("/") or _sCommand:find("\\") then - local sPath = shell.resolve( _sCommand ) - if fs.exists( sPath ) and not fs.isDir( sPath ) then + local sPath = shell.resolve(_sCommand) + if fs.exists(sPath) and not fs.isDir(sPath) then return sPath else - local sPathLua = pathWithExtension( sPath, "lua" ) - if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then + local sPathLua = pathWithExtension(sPath, "lua") + if fs.exists(sPathLua) and not fs.isDir(sPathLua) then return sPathLua end end @@ -249,12 +249,12 @@ function shell.resolveProgram( _sCommand ) -- Otherwise, look on the path variable for sPath in string.gmatch(sPath, "[^:]+") do - sPath = fs.combine( shell.resolve( sPath ), _sCommand ) - if fs.exists( sPath ) and not fs.isDir( sPath ) then + sPath = fs.combine(shell.resolve(sPath), _sCommand) + if fs.exists(sPath) and not fs.isDir(sPath) then return sPath else - local sPathLua = pathWithExtension( sPath, "lua" ) - if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then + local sPathLua = pathWithExtension(sPath, "lua") + if fs.exists(sPathLua) and not fs.isDir(sPathLua) then return sPathLua end end @@ -264,22 +264,22 @@ function shell.resolveProgram( _sCommand ) return nil end -function shell.programs( _bIncludeHidden ) +function shell.programs(_bIncludeHidden) local tItems = {} -- Add programs from the path for sPath in string.gmatch(sPath, "[^:]+") do - sPath = shell.resolve( sPath ) - if fs.isDir( sPath ) then - local tList = fs.list( sPath ) + sPath = shell.resolve(sPath) + if fs.isDir(sPath) then + local tList = fs.list(sPath) for n = 1, #tList do local sFile = tList[n] - if not fs.isDir( fs.combine( sPath, sFile ) ) and - (_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= ".") then + if not fs.isDir(fs.combine(sPath, sFile)) and + (_bIncludeHidden or string.sub(sFile, 1, 1) ~= ".") then if #sFile > 4 and sFile:sub(-4) == ".lua" then sFile = sFile:sub(1, -5) end - tItems[ sFile ] = true + tItems[sFile] = true end end end @@ -287,40 +287,40 @@ function shell.programs( _bIncludeHidden ) -- Sort and return local tItemList = {} - for sItem in pairs( tItems ) do - table.insert( tItemList, sItem ) + for sItem in pairs(tItems) do + table.insert(tItemList, sItem) end - table.sort( tItemList ) + table.sort(tItemList) return tItemList end -local function completeProgram( sLine ) +local function completeProgram(sLine) if #sLine > 0 and (sLine:find("/") or sLine:find("\\")) then -- Add programs from the root - return fs.complete( sLine, sDir, true, false ) + return fs.complete(sLine, sDir, true, false) else local tResults = {} local tSeen = {} -- Add aliases - for sAlias in pairs( tAliases ) do - if #sAlias > #sLine and string.sub( sAlias, 1, #sLine ) == sLine then - local sResult = string.sub( sAlias, #sLine + 1 ) - if not tSeen[ sResult ] then - table.insert( tResults, sResult ) - tSeen[ sResult ] = true + for sAlias in pairs(tAliases) do + if #sAlias > #sLine and string.sub(sAlias, 1, #sLine) == sLine then + local sResult = string.sub(sAlias, #sLine + 1) + if not tSeen[sResult] then + table.insert(tResults, sResult) + tSeen[sResult] = true end end end -- Add all subdirectories. We don't include files as they will be added in the block below - local tDirs = fs.complete( sLine, sDir, false, false ) + local tDirs = fs.complete(sLine, sDir, false, false) for i = 1, #tDirs do local sResult = tDirs[i] - if not tSeen[ sResult ] then - table.insert ( tResults, sResult ) - tSeen [ sResult ] = true + if not tSeen[sResult] then + table.insert (tResults, sResult) + tSeen [sResult] = true end end @@ -328,48 +328,48 @@ local function completeProgram( sLine ) local tPrograms = shell.programs() for n = 1, #tPrograms do local sProgram = tPrograms[n] - if #sProgram > #sLine and string.sub( sProgram, 1, #sLine ) == sLine then - local sResult = string.sub( sProgram, #sLine + 1 ) - if not tSeen[ sResult ] then - table.insert( tResults, sResult ) - tSeen[ sResult ] = true + if #sProgram > #sLine and string.sub(sProgram, 1, #sLine) == sLine then + local sResult = string.sub(sProgram, #sLine + 1) + if not tSeen[sResult] then + table.insert(tResults, sResult) + tSeen[sResult] = true end end end -- Sort and return - table.sort( tResults ) + table.sort(tResults) return tResults end end -local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousParts ) - local tInfo = tCompletionInfo[ sProgram ] +local function completeProgramArgument(sProgram, nArgument, sPart, tPreviousParts) + local tInfo = tCompletionInfo[sProgram] if tInfo then - return tInfo.fnComplete( shell, nArgument, sPart, tPreviousParts ) + return tInfo.fnComplete(shell, nArgument, sPart, tPreviousParts) end return nil end -function shell.complete( sLine ) +function shell.complete(sLine) expect(1, sLine, "string") if #sLine > 0 then - local tWords = tokenise( sLine ) + local tWords = tokenise(sLine) local nIndex = #tWords - if string.sub( sLine, #sLine, #sLine ) == " " then + if string.sub(sLine, #sLine, #sLine) == " " then nIndex = nIndex + 1 end if nIndex == 1 then local sBit = tWords[1] or "" - local sPath = shell.resolveProgram( sBit ) - if tCompletionInfo[ sPath ] then + local sPath = shell.resolveProgram(sBit) + if tCompletionInfo[sPath] then return { " " } else - local tResults = completeProgram( sBit ) + local tResults = completeProgram(sBit) for n = 1, #tResults do local sResult = tResults[n] - local sPath = shell.resolveProgram( sBit .. sResult ) - if tCompletionInfo[ sPath ] then + local sPath = shell.resolveProgram(sBit .. sResult) + if tCompletionInfo[sPath] then tResults[n] = sResult .. " " end end @@ -377,26 +377,26 @@ function shell.complete( sLine ) end elseif nIndex > 1 then - local sPath = shell.resolveProgram( tWords[1] ) + local sPath = shell.resolveProgram(tWords[1]) local sPart = tWords[nIndex] or "" local tPreviousParts = tWords tPreviousParts[nIndex] = nil - return completeProgramArgument( sPath , nIndex - 1, sPart, tPreviousParts ) + return completeProgramArgument(sPath , nIndex - 1, sPart, tPreviousParts) end end return nil end -function shell.completeProgram( sProgram ) +function shell.completeProgram(sProgram) expect(1, sProgram, "string") - return completeProgram( sProgram ) + return completeProgram(sProgram) end -function shell.setCompletionFunction( sProgram, fnComplete ) +function shell.setCompletionFunction(sProgram, fnComplete) expect(1, sProgram, "string") expect(2, fnComplete, "function") - tCompletionInfo[ sProgram ] = { + tCompletionInfo[sProgram] = { fnComplete = fnComplete, } end @@ -412,45 +412,45 @@ function shell.getRunningProgram() return nil end -function shell.setAlias( _sCommand, _sProgram ) +function shell.setAlias(_sCommand, _sProgram) expect(1, _sCommand, "string") expect(2, _sProgram, "string") - tAliases[ _sCommand ] = _sProgram + tAliases[_sCommand] = _sProgram end -function shell.clearAlias( _sCommand ) +function shell.clearAlias(_sCommand) expect(1, _sCommand, "string") - tAliases[ _sCommand ] = nil + tAliases[_sCommand] = nil end function shell.aliases() -- Copy aliases local tCopy = {} - for sAlias, sCommand in pairs( tAliases ) do + for sAlias, sCommand in pairs(tAliases) do tCopy[sAlias] = sCommand end return tCopy end if multishell then - function shell.openTab( ... ) - local tWords = tokenise( ... ) + function shell.openTab(...) + local tWords = tokenise(...) local sCommand = tWords[1] if sCommand then - local sPath = shell.resolveProgram( sCommand ) + local sPath = shell.resolveProgram(sCommand) if sPath == "rom/programs/shell.lua" then - return multishell.launch( createShellEnv( "rom/programs" ), sPath, table.unpack( tWords, 2 ) ) + return multishell.launch(createShellEnv("rom/programs"), sPath, table.unpack(tWords, 2)) elseif sPath ~= nil then - return multishell.launch( createShellEnv( "rom/programs" ), "rom/programs/shell.lua", sCommand, table.unpack( tWords, 2 ) ) + return multishell.launch(createShellEnv("rom/programs"), "rom/programs/shell.lua", sCommand, table.unpack(tWords, 2)) else - printError( "No such program" ) + printError("No such program") end end end - function shell.switchTab( nID ) + function shell.switchTab(nID) expect(1, nID, "number") - multishell.setFocus( nID ) + multishell.setFocus(nID) end end @@ -458,40 +458,40 @@ local tArgs = { ... } if #tArgs > 0 then -- "shell x y z" -- Run the program specified on the commandline - shell.run( ... ) + shell.run(...) else -- "shell" -- Print the header - term.setBackgroundColor( bgColour ) - term.setTextColour( promptColour ) - print( os.version() ) - term.setTextColour( textColour ) + term.setBackgroundColor(bgColour) + term.setTextColour(promptColour) + print(os.version()) + term.setTextColour(textColour) -- Run the startup program if parentShell == nil then - shell.run( "/rom/startup.lua" ) + shell.run("/rom/startup.lua") end -- Read commands and execute them local tCommandHistory = {} while not bExit do - term.redirect( parentTerm ) - term.setBackgroundColor( bgColour ) - term.setTextColour( promptColour ) - write( shell.dir() .. "> " ) - term.setTextColour( textColour ) + term.redirect(parentTerm) + term.setBackgroundColor(bgColour) + term.setTextColour(promptColour) + write(shell.dir() .. "> ") + term.setTextColour(textColour) local sLine - if settings.get( "shell.autocomplete" ) then - sLine = read( nil, tCommandHistory, shell.complete ) + if settings.get("shell.autocomplete") then + sLine = read(nil, tCommandHistory, shell.complete) else - sLine = read( nil, tCommandHistory ) + sLine = read(nil, tCommandHistory) end if sLine:match("%S") and tCommandHistory[#tCommandHistory] ~= sLine then - table.insert( tCommandHistory, sLine ) + table.insert(tCommandHistory, sLine) end - shell.run( sLine ) + shell.run(sLine) end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/shutdown.lua b/src/main/resources/data/computercraft/lua/rom/programs/shutdown.lua index 052409eeb..b895c571f 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/shutdown.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/shutdown.lua @@ -1,8 +1,8 @@ if term.isColour() then - term.setTextColour( colours.yellow ) + term.setTextColour(colours.yellow) end -print( "Goodbye" ) -term.setTextColour( colours.white ) +print("Goodbye") +term.setTextColour(colours.white) -sleep( 1 ) +sleep(1) os.shutdown() diff --git a/src/main/resources/data/computercraft/lua/rom/programs/time.lua b/src/main/resources/data/computercraft/lua/rom/programs/time.lua index ccd83d4ec..988846013 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/time.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/time.lua @@ -1,3 +1,3 @@ local nTime = os.time() local nDay = os.day() -print( "The time is " .. textutils.formatTime( nTime, false ) .. " on Day " .. nDay ) +print("The time is " .. textutils.formatTime(nTime, false) .. " on Day " .. nDay) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/craft.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/craft.lua index 8b8923e71..65f93104b 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/craft.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/craft.lua @@ -1,26 +1,26 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end if not turtle.craft then - print( "Requires a Crafty Turtle" ) + print("Requires a Crafty Turtle") return end local tArgs = { ... } local nLimit = nil if #tArgs < 1 then - print( "Usage: craft [number]" ) + print("Usage: craft [number]") return else - nLimit = tonumber( tArgs[1] ) + nLimit = tonumber(tArgs[1]) end local nCrafted = 0 -local nOldCount = turtle.getItemCount( turtle.getSelectedSlot() ) -if turtle.craft( nLimit ) then - local nNewCount = turtle.getItemCount( turtle.getSelectedSlot() ) +local nOldCount = turtle.getItemCount(turtle.getSelectedSlot()) +if turtle.craft(nLimit) then + local nNewCount = turtle.getItemCount(turtle.getSelectedSlot()) if nOldCount <= nLimit then nCrafted = nNewCount else @@ -29,9 +29,9 @@ if turtle.craft( nLimit ) then end if nCrafted > 1 then - print( nCrafted .. " items crafted" ) + print(nCrafted .. " items crafted") elseif nCrafted == 1 then - print( "1 item crafted" ) + print("1 item crafted") else - print( "No items crafted" ) + print("No items crafted") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/dance.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/dance.lua index 696c15747..9d539fde4 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/dance.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/dance.lua @@ -1,5 +1,5 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") end local tMoves = { @@ -77,20 +77,20 @@ local tMoves = { end, } -textutils.slowWrite( "Preparing to get down." ) -textutils.slowPrint( "..", 0.75 ) +textutils.slowWrite("Preparing to get down.") +textutils.slowPrint("..", 0.75) local sAudio = nil -for _, sName in pairs( peripheral.getNames() ) do - if disk.hasAudio( sName ) then - disk.playAudio( sName ) - print( "Jamming to " .. disk.getAudioTitle( sName ) ) +for _, sName in pairs(peripheral.getNames()) do + if disk.hasAudio(sName) then + disk.playAudio(sName) + print("Jamming to " .. disk.getAudioTitle(sName)) sAudio = sName break end end -print( "Press any key to stop the groove" ) +print("Press any key to stop the groove") parallel.waitForAny( function() @@ -110,5 +110,5 @@ parallel.waitForAny( ) if sAudio then - disk.stopAudio( sAudio ) + disk.stopAudio(sAudio) end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/equip.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/equip.lua index 0a8f2a480..b69ef4c45 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/equip.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/equip.lua @@ -1,11 +1,11 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } local function printUsage() - print( "Usage: equip " ) + print("Usage: equip ") end if #tArgs ~= 2 then @@ -13,29 +13,29 @@ if #tArgs ~= 2 then return end -local function equip( nSlot, fnEquipFunction ) - turtle.select( nSlot ) - local nOldCount = turtle.getItemCount( nSlot ) +local function equip(nSlot, fnEquipFunction) + turtle.select(nSlot) + local nOldCount = turtle.getItemCount(nSlot) if nOldCount == 0 then - print( "Nothing to equip" ) + print("Nothing to equip") elseif fnEquipFunction() then - local nNewCount = turtle.getItemCount( nSlot ) + local nNewCount = turtle.getItemCount(nSlot) if nNewCount > 0 then - print( "Items swapped" ) + print("Items swapped") else - print( "Item equipped" ) + print("Item equipped") end else - print( "Item not equippable" ) + print("Item not equippable") end end -local nSlot = tonumber( tArgs[1] ) +local nSlot = tonumber(tArgs[1]) local sSide = tArgs[2] if sSide == "left" then - equip( nSlot, turtle.equipLeft ) + equip(nSlot, turtle.equipLeft) elseif sSide == "right" then - equip( nSlot, turtle.equipRight ) + equip(nSlot, turtle.equipRight) else printUsage() return diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/excavate.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/excavate.lua index 2edc5b1fa..9d4313eb1 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/excavate.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/excavate.lua @@ -1,18 +1,18 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } if #tArgs ~= 1 then - print( "Usage: excavate " ) + print("Usage: excavate ") return end -- Mine in a quarry pattern until we hit something we can't dig -local size = tonumber( tArgs[1] ) +local size = tonumber(tArgs[1]) if size < 1 then - print( "Excavate diameter must be positive" ) + print("Excavate diameter must be positive") return end @@ -26,8 +26,8 @@ local xDir, zDir = 0, 1 local goTo -- Filled in further down local refuel -- Filled in further down -local function unload( _bKeepOneFuelStack ) - print( "Unloading items..." ) +local function unload(_bKeepOneFuelStack) + print("Unloading items...") for n = 1, 16 do local nCount = turtle.getItemCount(n) if nCount > 0 then @@ -49,22 +49,22 @@ end local function returnSupplies() local x, y, z, xd, zd = xPos, depth, zPos, xDir, zDir - print( "Returning to surface..." ) - goTo( 0, 0, 0, 0, -1 ) + print("Returning to surface...") + goTo(0, 0, 0, 0, -1) local fuelNeeded = 2 * (x + y + z) + 1 - if not refuel( fuelNeeded ) then - unload( true ) - print( "Waiting for fuel" ) - while not refuel( fuelNeeded ) do - os.pullEvent( "turtle_inventory" ) + if not refuel(fuelNeeded) then + unload(true) + print("Waiting for fuel") + while not refuel(fuelNeeded) do + os.pullEvent("turtle_inventory") end else - unload( true ) + unload(true) end - print( "Resuming mining..." ) - goTo( x, y, z, xd, zd ) + print("Resuming mining...") + goTo(x, y, z, xd, zd) end local function collect() @@ -81,18 +81,18 @@ local function collect() if nTotalItems > collected then collected = nTotalItems if math.fmod(collected + unloaded, 50) == 0 then - print( "Mined " .. collected + unloaded .. " items." ) + print("Mined " .. collected + unloaded .. " items.") end end if bFull then - print( "No empty slots left." ) + print("No empty slots left.") return false end return true end -function refuel( ammount ) +function refuel(ammount) local fuelLevel = turtle.getFuelLevel() if fuelLevel == "unlimited" then return true @@ -123,7 +123,7 @@ end local function tryForwards() if not refuel() then - print( "Not enough Fuel" ) + print("Not enough Fuel") returnSupplies() end @@ -141,7 +141,7 @@ local function tryForwards() returnSupplies() end else - sleep( 0.5 ) + sleep(0.5) end end @@ -152,7 +152,7 @@ end local function tryDown() if not refuel() then - print( "Not enough Fuel" ) + print("Not enough Fuel") returnSupplies() end @@ -170,13 +170,13 @@ local function tryDown() returnSupplies() end else - sleep( 0.5 ) + sleep(0.5) end end depth = depth + 1 - if math.fmod( depth, 10 ) == 0 then - print( "Descended " .. depth .. " metres." ) + if math.fmod(depth, 10) == 0 then + print("Descended " .. depth .. " metres.") end return true @@ -192,14 +192,14 @@ local function turnRight() xDir, zDir = zDir, -xDir end -function goTo( x, y, z, xd, zd ) +function goTo(x, y, z, xd, zd) while depth > y do if turtle.up() then depth = depth - 1 elseif turtle.digUp() or turtle.attackUp() then collect() else - sleep( 0.5 ) + sleep(0.5) end end @@ -213,7 +213,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.dig() or turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end elseif xPos < x then @@ -226,7 +226,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.dig() or turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end end @@ -241,7 +241,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.dig() or turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end elseif zPos < z then @@ -254,7 +254,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.dig() or turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end end @@ -265,7 +265,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.digDown() or turtle.attackDown() then collect() else - sleep( 0.5 ) + sleep(0.5) end end @@ -275,11 +275,11 @@ function goTo( x, y, z, xd, zd ) end if not refuel() then - print( "Out of Fuel" ) + print("Out of Fuel") return end -print( "Excavating..." ) +print("Excavating...") local reseal = false turtle.select(1) @@ -341,16 +341,16 @@ while not done do end end -print( "Returning to surface..." ) +print("Returning to surface...") -- Return to where we started -goTo( 0, 0, 0, 0, -1 ) -unload( false ) -goTo( 0, 0, 0, 0, 1 ) +goTo(0, 0, 0, 0, -1) +unload(false) +goTo(0, 0, 0, 0, 1) -- Seal the hole if reseal then turtle.placeDown() end -print( "Mined " .. collected + unloaded .. " items total." ) +print("Mined " .. collected + unloaded .. " items total.") diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/go.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/go.lua index c8b43b0e9..9c6de67ce 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/go.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/go.lua @@ -1,11 +1,11 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } if #tArgs < 1 then - print( "Usage: go " ) + print("Usage: go ") return end @@ -29,7 +29,7 @@ while nArg <= #tArgs do local sDirection = tArgs[nArg] local nDistance = 1 if nArg < #tArgs then - local num = tonumber( tArgs[nArg + 1] ) + local num = tonumber(tArgs[nArg + 1]) if num then nDistance = num nArg = nArg + 1 @@ -43,15 +43,15 @@ while nArg <= #tArgs do if fnHandler() then nDistance = nDistance - 1 elseif turtle.getFuelLevel() == 0 then - print( "Out of fuel" ) + print("Out of fuel") return else sleep(0.5) end end else - print( "No such direction: " .. sDirection ) - print( "Try: forward, back, up, down" ) + print("No such direction: " .. sDirection) + print("Try: forward, back, up, down") return end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/refuel.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/refuel.lua index 77f796196..d9dd5b002 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/refuel.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/refuel.lua @@ -1,18 +1,18 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } local nLimit = 1 if #tArgs > 1 then - print( "Usage: refuel [number]" ) + print("Usage: refuel [number]") return elseif #tArgs > 0 then if tArgs[1] == "all" then nLimit = nil else - nLimit = tonumber( tArgs[1] ) + nLimit = tonumber(tArgs[1]) if not nLimit then print("Invalid limit, expected a number or \"all\"") return @@ -29,17 +29,17 @@ if turtle.getFuelLevel() ~= "unlimited" then local nCount = turtle.getItemCount(n) if nCount > 0 then - turtle.select( n ) - if turtle.refuel( nLimit ) and nLimit then + turtle.select(n) + if turtle.refuel(nLimit) and nLimit then local nNewCount = turtle.getItemCount(n) nLimit = nLimit - (nCount - nNewCount) end end end - print( "Fuel level is " .. turtle.getFuelLevel() ) + print("Fuel level is " .. turtle.getFuelLevel()) if turtle.getFuelLevel() == turtle.getFuelLimit() then - print( "Fuel limit reached" ) + print("Fuel limit reached") end else - print( "Fuel level is unlimited" ) + print("Fuel level is unlimited") end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/tunnel.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/tunnel.lua index 50183d013..34c0807d9 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/tunnel.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/tunnel.lua @@ -1,18 +1,18 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } if #tArgs ~= 1 then - print( "Usage: tunnel " ) + print("Usage: tunnel ") return end -- Mine in a quarry pattern until we hit something we can't dig -local length = tonumber( tArgs[1] ) +local length = tonumber(tArgs[1]) if length < 1 then - print( "Tunnel length must be positive" ) + print("Tunnel length must be positive") return end local collected = 0 @@ -20,7 +20,7 @@ local collected = 0 local function collect() collected = collected + 1 if math.fmod(collected, 25) == 0 then - print( "Mined " .. collected .. " items." ) + print("Mined " .. collected .. " items.") end end @@ -81,11 +81,11 @@ local function refuel() end if not tryRefuel() then - print( "Add more fuel to continue." ) + print("Add more fuel to continue.") while not tryRefuel() do - os.pullEvent( "turtle_inventory" ) + os.pullEvent("turtle_inventory") end - print( "Resuming Tunnel." ) + print("Resuming Tunnel.") end end @@ -99,7 +99,7 @@ local function tryUp() elseif turtle.attackUp() then collect() else - sleep( 0.5 ) + sleep(0.5) end end return true @@ -115,7 +115,7 @@ local function tryDown() elseif turtle.attackDown() then collect() else - sleep( 0.5 ) + sleep(0.5) end end return true @@ -131,13 +131,13 @@ local function tryForward() elseif turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end return true end -print( "Tunnelling..." ) +print("Tunnelling...") for n = 1, length do turtle.placeDown() @@ -156,11 +156,11 @@ for n = 1, length do if n < length then tryDig() if not tryForward() then - print( "Aborting Tunnel." ) + print("Aborting Tunnel.") break end else - print( "Tunnel complete." ) + print("Tunnel complete.") end end @@ -182,5 +182,5 @@ turtle.turnRight() turtle.turnRight() ]] -print( "Tunnel complete." ) -print( "Mined " .. collected .. " items total." ) +print("Tunnel complete.") +print("Mined " .. collected .. " items total.") diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/turn.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/turn.lua index d34db5753..e3fbbcbd3 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/turn.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/turn.lua @@ -1,11 +1,11 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } if #tArgs < 1 then - print( "Usage: turn " ) + print("Usage: turn ") return end @@ -21,7 +21,7 @@ while nArg <= #tArgs do local sDirection = tArgs[nArg] local nDistance = 1 if nArg < #tArgs then - local num = tonumber( tArgs[nArg + 1] ) + local num = tonumber(tArgs[nArg + 1]) if num then nDistance = num nArg = nArg + 1 @@ -32,11 +32,11 @@ while nArg <= #tArgs do local fnHandler = tHandlers[string.lower(sDirection)] if fnHandler then for _ = 1, nDistance do - fnHandler( nArg ) + fnHandler(nArg) end else - print( "No such direction: " .. sDirection ) - print( "Try: left, right" ) + print("No such direction: " .. sDirection) + print("Try: left, right") return end end diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/unequip.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/unequip.lua index e19672577..97501aa42 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/unequip.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/unequip.lua @@ -1,11 +1,11 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } local function printUsage() - print( "Usage: unequip " ) + print("Usage: unequip ") end if #tArgs ~= 1 then @@ -13,31 +13,31 @@ if #tArgs ~= 1 then return end -local function unequip( fnEquipFunction ) +local function unequip(fnEquipFunction) for nSlot = 1, 16 do - local nOldCount = turtle.getItemCount( nSlot ) + local nOldCount = turtle.getItemCount(nSlot) if nOldCount == 0 then - turtle.select( nSlot ) + turtle.select(nSlot) if fnEquipFunction() then - local nNewCount = turtle.getItemCount( nSlot ) + local nNewCount = turtle.getItemCount(nSlot) if nNewCount > 0 then - print( "Item unequipped" ) + print("Item unequipped") return else - print( "Nothing to unequip" ) + print("Nothing to unequip") return end end end end - print( "No space to unequip item" ) + print("No space to unequip item") end local sSide = tArgs[1] if sSide == "left" then - unequip( turtle.equipLeft ) + unequip(turtle.equipLeft) elseif sSide == "right" then - unequip( turtle.equipRight ) + unequip(turtle.equipRight) else printUsage() return diff --git a/src/main/resources/data/computercraft/lua/rom/programs/type.lua b/src/main/resources/data/computercraft/lua/rom/programs/type.lua index c2fabbbaf..ec0ebc0c5 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/type.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/type.lua @@ -1,18 +1,18 @@ local tArgs = { ... } if #tArgs < 1 then - print( "Usage: type " ) + print("Usage: type ") return end -local sPath = shell.resolve( tArgs[1] ) -if fs.exists( sPath ) then - if fs.isDir( sPath ) then - print( "directory" ) +local sPath = shell.resolve(tArgs[1]) +if fs.exists(sPath) then + if fs.isDir(sPath) then + print("directory") else - print( "file" ) + print("file") end else - print( "No such path" ) + print("No such path") end diff --git a/src/main/resources/data/computercraft/lua/rom/startup.lua b/src/main/resources/data/computercraft/lua/rom/startup.lua index dcefffb93..1b3046092 100644 --- a/src/main/resources/data/computercraft/lua/rom/startup.lua +++ b/src/main/resources/data/computercraft/lua/rom/startup.lua @@ -22,130 +22,130 @@ end if http then sPath = sPath .. ":/rom/programs/http" end -shell.setPath( sPath ) -help.setPath( "/rom/help" ) +shell.setPath(sPath) +help.setPath("/rom/help") -- Setup aliases -shell.setAlias( "ls", "list" ) -shell.setAlias( "dir", "list" ) -shell.setAlias( "cp", "copy" ) -shell.setAlias( "mv", "move" ) -shell.setAlias( "rm", "delete" ) -shell.setAlias( "clr", "clear" ) -shell.setAlias( "rs", "redstone" ) -shell.setAlias( "sh", "shell" ) +shell.setAlias("ls", "list") +shell.setAlias("dir", "list") +shell.setAlias("cp", "copy") +shell.setAlias("mv", "move") +shell.setAlias("rm", "delete") +shell.setAlias("clr", "clear") +shell.setAlias("rs", "redstone") +shell.setAlias("sh", "shell") if term.isColor() then - shell.setAlias( "background", "bg" ) - shell.setAlias( "foreground", "fg" ) + shell.setAlias("background", "bg") + shell.setAlias("foreground", "fg") end -- Setup completion functions local function completePastebinPut(shell, text, previous) if previous[2] == "put" then - return fs.complete(text, shell.dir(), true, false ) + return fs.complete(text, shell.dir(), true, false) end end -shell.setCompletionFunction( "rom/programs/alias.lua", completion.build(nil, completion.program) ) -shell.setCompletionFunction( "rom/programs/cd.lua", completion.build(completion.dir) ) -shell.setCompletionFunction( "rom/programs/copy.lua", completion.build( +shell.setCompletionFunction("rom/programs/alias.lua", completion.build(nil, completion.program)) +shell.setCompletionFunction("rom/programs/cd.lua", completion.build(completion.dir)) +shell.setCompletionFunction("rom/programs/copy.lua", completion.build( { completion.dirOrFile, true }, completion.dirOrFile -) ) -shell.setCompletionFunction( "rom/programs/delete.lua", completion.build({ completion.dirOrFile, many = true }) ) -shell.setCompletionFunction( "rom/programs/drive.lua", completion.build(completion.dir) ) -shell.setCompletionFunction( "rom/programs/edit.lua", completion.build(completion.file) ) -shell.setCompletionFunction( "rom/programs/eject.lua", completion.build(completion.peripheral) ) -shell.setCompletionFunction( "rom/programs/gps.lua", completion.build({ completion.choice, { "host", "host ", "locate" } }) ) -shell.setCompletionFunction( "rom/programs/help.lua", completion.build(completion.help) ) -shell.setCompletionFunction( "rom/programs/id.lua", completion.build(completion.peripheral) ) -shell.setCompletionFunction( "rom/programs/label.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/delete.lua", completion.build({ completion.dirOrFile, many = true })) +shell.setCompletionFunction("rom/programs/drive.lua", completion.build(completion.dir)) +shell.setCompletionFunction("rom/programs/edit.lua", completion.build(completion.file)) +shell.setCompletionFunction("rom/programs/eject.lua", completion.build(completion.peripheral)) +shell.setCompletionFunction("rom/programs/gps.lua", completion.build({ completion.choice, { "host", "host ", "locate" } })) +shell.setCompletionFunction("rom/programs/help.lua", completion.build(completion.help)) +shell.setCompletionFunction("rom/programs/id.lua", completion.build(completion.peripheral)) +shell.setCompletionFunction("rom/programs/label.lua", completion.build( { completion.choice, { "get", "get ", "set ", "clear", "clear " } }, completion.peripheral -) ) -shell.setCompletionFunction( "rom/programs/list.lua", completion.build(completion.dir) ) -shell.setCompletionFunction( "rom/programs/mkdir.lua", completion.build({ completion.dir, many = true }) ) -shell.setCompletionFunction( "rom/programs/monitor.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/list.lua", completion.build(completion.dir)) +shell.setCompletionFunction("rom/programs/mkdir.lua", completion.build({ completion.dir, many = true })) +shell.setCompletionFunction("rom/programs/monitor.lua", completion.build( { completion.peripheral, true }, completion.program -) ) -shell.setCompletionFunction( "rom/programs/move.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/move.lua", completion.build( { completion.dirOrFile, true }, completion.dirOrFile -) ) -shell.setCompletionFunction( "rom/programs/redstone.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/redstone.lua", completion.build( { completion.choice, { "probe", "set ", "pulse " } }, completion.side -) ) -shell.setCompletionFunction( "rom/programs/rename.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/rename.lua", completion.build( { completion.dirOrFile, true }, completion.dirOrFile -) ) -shell.setCompletionFunction( "rom/programs/shell.lua", completion.build(completion.program) ) -shell.setCompletionFunction( "rom/programs/type.lua", completion.build(completion.dirOrFile) ) -shell.setCompletionFunction( "rom/programs/set.lua", completion.build({ completion.setting, true }) ) -shell.setCompletionFunction( "rom/programs/advanced/bg.lua", completion.build(completion.program) ) -shell.setCompletionFunction( "rom/programs/advanced/fg.lua", completion.build(completion.program) ) -shell.setCompletionFunction( "rom/programs/fun/dj.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/shell.lua", completion.build(completion.program)) +shell.setCompletionFunction("rom/programs/type.lua", completion.build(completion.dirOrFile)) +shell.setCompletionFunction("rom/programs/set.lua", completion.build({ completion.setting, true })) +shell.setCompletionFunction("rom/programs/advanced/bg.lua", completion.build(completion.program)) +shell.setCompletionFunction("rom/programs/advanced/fg.lua", completion.build(completion.program)) +shell.setCompletionFunction("rom/programs/fun/dj.lua", completion.build( { completion.choice, { "play", "play ", "stop " } }, completion.peripheral -) ) -shell.setCompletionFunction( "rom/programs/fun/advanced/paint.lua", completion.build(completion.file) ) -shell.setCompletionFunction( "rom/programs/http/pastebin.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/fun/advanced/paint.lua", completion.build(completion.file)) +shell.setCompletionFunction("rom/programs/http/pastebin.lua", completion.build( { completion.choice, { "put ", "get ", "run " } }, completePastebinPut -) ) -shell.setCompletionFunction( "rom/programs/rednet/chat.lua", completion.build({ completion.choice, { "host ", "join " } }) ) -shell.setCompletionFunction( "rom/programs/command/exec.lua", completion.build(completion.command) ) -shell.setCompletionFunction( "rom/programs/http/wget.lua", completion.build({ completion.choice, { "run " } }) ) +)) +shell.setCompletionFunction("rom/programs/rednet/chat.lua", completion.build({ completion.choice, { "host ", "join " } })) +shell.setCompletionFunction("rom/programs/command/exec.lua", completion.build(completion.command)) +shell.setCompletionFunction("rom/programs/http/wget.lua", completion.build({ completion.choice, { "run " } })) if turtle then - shell.setCompletionFunction( "rom/programs/turtle/go.lua", completion.build( + shell.setCompletionFunction("rom/programs/turtle/go.lua", completion.build( { completion.choice, { "left", "right", "forward", "back", "down", "up" }, true, many = true } - ) ) - shell.setCompletionFunction( "rom/programs/turtle/turn.lua", completion.build( + )) + shell.setCompletionFunction("rom/programs/turtle/turn.lua", completion.build( { completion.choice, { "left", "right" }, true, many = true } )) - shell.setCompletionFunction( "rom/programs/turtle/equip.lua", completion.build( + shell.setCompletionFunction("rom/programs/turtle/equip.lua", completion.build( nil, { completion.choice, { "left", "right" } } - ) ) - shell.setCompletionFunction( "rom/programs/turtle/unequip.lua", completion.build( + )) + shell.setCompletionFunction("rom/programs/turtle/unequip.lua", completion.build( { completion.choice, { "left", "right" } } - ) ) + )) end -- Run autorun files -if fs.exists( "/rom/autorun" ) and fs.isDir( "/rom/autorun" ) then - local tFiles = fs.list( "/rom/autorun" ) - for _, sFile in ipairs( tFiles ) do - if string.sub( sFile, 1, 1 ) ~= "." then +if fs.exists("/rom/autorun") and fs.isDir("/rom/autorun") then + local tFiles = fs.list("/rom/autorun") + for _, sFile in ipairs(tFiles) do + if string.sub(sFile, 1, 1) ~= "." then local sPath = "/rom/autorun/" .. sFile - if not fs.isDir( sPath ) then - shell.run( sPath ) + if not fs.isDir(sPath) then + shell.run(sPath) end end end end -local function findStartups( sBaseDir ) +local function findStartups(sBaseDir) local tStartups = nil - local sBasePath = "/" .. fs.combine( sBaseDir, "startup" ) - local sStartupNode = shell.resolveProgram( sBasePath ) + local sBasePath = "/" .. fs.combine(sBaseDir, "startup") + local sStartupNode = shell.resolveProgram(sBasePath) if sStartupNode then tStartups = { sStartupNode } end -- It's possible that there is a startup directory and a startup.lua file, so this has to be -- executed even if a file has already been found. - if fs.isDir( sBasePath ) then + if fs.isDir(sBasePath) then if tStartups == nil then tStartups = {} end - for _, v in pairs( fs.list( sBasePath ) ) do - local sPath = "/" .. fs.combine( sBasePath, v ) - if not fs.isDir( sPath ) then - tStartups[ #tStartups + 1 ] = sPath + for _, v in pairs(fs.list(sBasePath)) do + local sPath = "/" .. fs.combine(sBasePath, v) + if not fs.isDir(sPath) then + tStartups[#tStartups + 1] = sPath end end end @@ -153,19 +153,19 @@ local function findStartups( sBaseDir ) end -- Show MOTD -if settings.get( "motd.enable" ) then - shell.run( "motd" ) +if settings.get("motd.enable") then + shell.run("motd") end -- Run the user created startup, either from disk drives or the root local tUserStartups = nil -if settings.get( "shell.allow_startup" ) then - tUserStartups = findStartups( "/" ) +if settings.get("shell.allow_startup") then + tUserStartups = findStartups("/") end -if settings.get( "shell.allow_disk_startup" ) then - for _, sName in pairs( peripheral.getNames() ) do - if disk.isPresent( sName ) and disk.hasData( sName ) then - local startups = findStartups( disk.getMountPath( sName ) ) +if settings.get("shell.allow_disk_startup") then + for _, sName in pairs(peripheral.getNames()) do + if disk.isPresent(sName) and disk.hasData(sName) then + local startups = findStartups(disk.getMountPath(sName)) if startups then tUserStartups = startups break @@ -174,7 +174,7 @@ if settings.get( "shell.allow_disk_startup" ) then end end if tUserStartups then - for _, v in pairs( tUserStartups ) do - shell.run( v ) + for _, v in pairs(tUserStartups) do + shell.run(v) end end diff --git a/src/main/resources/data/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua b/src/main/resources/data/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua index 03431406c..8d48eaaf5 100644 --- a/src/main/resources/data/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua +++ b/src/main/resources/data/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua @@ -1,8 +1,8 @@ --[[ battleship, - + by GopherAtl, 2013 - + Do whatever you want, just don't judge me by what a mess this code is. --]] @@ -17,21 +17,21 @@ local myTurn local targetX,targetY local shipsLeft=5 local oppShipsLeft=5 - + local originalTerm = term.current() - + --bounding box of the target grid local targetGridBounds={ minX=16, maxX=25, minY=4, maxY=13 } - - + + local function doColor(text,background) term.setTextColor(text) term.setBackgroundColor(background) end - + local function doColor_mono(text,background) if text==colors.blue or text==colors.red or text==colors.black or text==colors.lime or background==colors.lightGray then term.setTextColor(colors.black) @@ -39,9 +39,9 @@ local function doColor_mono(text,background) else term.setTextColor(colors.white) term.setBackgroundColor(colors.black) - end + end end - + local function doScreenColor() if term.isColor() then doColor(colors.white,colors.lightGray) @@ -49,16 +49,16 @@ local function doScreenColor() doColor(colors.black,colors.white) end end - + local function toGridRef(x,y) return string.sub("ABCDEFGHIJ",x,x)..string.sub("1234567890",y,y) end - - + + if not term.isColor() then doColor=doColor_mono end - + local function quit() if openedSide then rednet.close(openedSide) @@ -68,7 +68,7 @@ local function quit() print() error() end - + local foundModem=false --find modem for k,v in pairs(redstone.getSides()) do @@ -81,17 +81,17 @@ for k,v in pairs(redstone.getSides()) do break end end - + if not foundModem then print("You must have a modem to play!") return end - + if action==nil or (action~="join" and action~="host") then print("Invalid parameters. Usage:\n> battleship host\nHosts a game, waits for another computer to join\n> battleship join\nLooks for another game to join") quit() end - + --get player name while true do doColor(colors.cyan,colors.black) @@ -108,13 +108,13 @@ while true do break end end - + if action=="join" then print("Attempting to join a game...\n(press q to cancel)") while true do local retryTimer=os.startTimer(1); rednet.broadcast("bs join "..myName); - + while true do local event,p1,p2,p3=os.pullEvent(); if event=="rednet_message" then @@ -131,7 +131,7 @@ if action=="join" then end end local joined=false - + if opponentID then print("Joining game!") rednet.send(opponentID,"bs start") @@ -142,7 +142,7 @@ elseif action=="host" then print("Waiting for challenger...\n(Press q to cancel)") while true do while true do - local event,p1,p2=os.pullEvent() + local event,p1,p2=os.pullEvent() if event=="rednet_message" then opponent=string.match(p2,"bs join %s*(.+)%s*") if opponent then print("found player, inviting..") @@ -154,7 +154,7 @@ elseif action=="host" then quit() end end - + if opponentID then rednet.send(opponentID,"bs accept "..myName) local timeout=os.startTimer(1) @@ -166,17 +166,17 @@ elseif action=="host" then elseif event=="timer" and p1==timeout then print("player joined another game. Waiting for another...") opponentID=nil - break + break end end - + if opponentID then break end end end end - + local ships={ {pos=nil,dir="h",size=5,name="carrier",hits=0}, {pos=nil,dir="h",size=4,name="battleship",hits=0}, @@ -184,12 +184,12 @@ local ships={ {pos=nil,dir="h",size=3,name="submarine",hits=0}, {pos=nil,dir="h",size=2,name="destroyer",hits=0}, } - + local myShotTable={ {1,1,true},{5,5,false} } local oppShotTable={ } - + local myGrid,oppGrid={title=myName},{title=opponent} - + --setup grids for i=1,10 do myGrid[i]={} @@ -199,8 +199,8 @@ for i=1,10 do oppGrid[i][j]={hit=false,ship=false} end end - -local function drawShipsToGrid(ships,grid) + +local function drawShipsToGrid(ships,grid) for i=1,#ships do local x,y=table.unpack(ships[i].pos) local stepX=ships[i].dir=="h" and 1 or 0 @@ -211,18 +211,18 @@ local function drawShipsToGrid(ships,grid) end end end - + local function drawShotToGrid(shot,grid) grid[shot[1]][shot[2]].shot=true - grid[shot[1]][shot[2]].hit=shot[3] + grid[shot[1]][shot[2]].hit=shot[3] end - + local function makeShot(x,y,grid) local tile=grid[x][y] if tile.shot==true then return nil --already shot here! - end - + end + local shot={x,y,tile.ship} drawShotToGrid(shot,grid) if tile.ship then @@ -232,12 +232,12 @@ local function makeShot(x,y,grid) end end return shot -end - - +end + + local function drawTile(scrX,scrY,tile) term.setCursorPos(scrX,scrY) - + if tile.ship then if tile.shot then doColor(colors.red,colors.gray) @@ -259,31 +259,31 @@ local function drawTile(scrX,scrY,tile) end end end - + local function drawGrid(scrX,scrY,grid) doColor(colors.white,colors.black) term.setCursorPos(scrX,scrY+1) term.write(" ") - doColor(colors.white,colors.gray) + doColor(colors.white,colors.gray) term.setCursorPos(scrX,scrY) local pad=11-#grid.title term.write(string.rep(" ",math.ceil(pad/2))..grid.title..string.rep(" ",math.floor(pad/2))) - + for gx=1,10 do term.setTextColor(colors.white) term.setBackgroundColor(colors.black) term.setCursorPos(scrX+gx,scrY+1) term.write(gx==10 and "0" or string.char(string.byte("0")+gx)) - + term.setCursorPos(scrX,scrY+gx+1) term.write(string.char(string.byte("A")+gx-1)) for gy=1,10 do - drawTile(scrX+gx,scrY+gy+1,grid[gx][gy]) + drawTile(scrX+gx,scrY+gy+1,grid[gx][gy]) end end doColor(colors.white,colors.black) end - + function moveTargetIndicator(newX,newY) --if x has changed... if targetX and targetY then @@ -303,8 +303,8 @@ function moveTargetIndicator(newX,newY) term.write("^") term.setCursorPos(targetGridBounds.minX+newX-1,targetGridBounds.minY-3) term.write("v") - - targetX=newX + + targetX=newX end if newY~=targetY then --space over old @@ -319,11 +319,11 @@ function moveTargetIndicator(newX,newY) term.write("<") term.setCursorPos(targetGridBounds.minX-2,targetGridBounds.minY+newY-1) term.write(">") - + targetY=newY end term.setCursorPos(15,15) - term.write("Target : "..toGridRef(targetX,targetY)) + term.write("Target : "..toGridRef(targetX,targetY)) --if the target tile is a valid target, draw a "+" if not oppGrid[targetX][targetY].shot then term.setCursorPos(targetX+targetGridBounds.minX-1,targetY+targetGridBounds.minY-1) @@ -331,18 +331,18 @@ function moveTargetIndicator(newX,newY) term.write("+") end end - + local log={} - + local termWidth,termHeight=term.getSize() - + local logHeight=termHeight-3 local logWidth=termWidth-28 - + for i=1,logHeight do log[i]="" end - + local function printLog() doColor(colors.white,colors.black) for i=1,logHeight do @@ -358,9 +358,9 @@ local function printLog() end end end - - - + + + --shipX/Y are the position of ship on grid; gridX/Y are the offset of the top-left of grid local function drawShip(size,align,x,y,char) local stepX=align=="h" and 1 or 0 @@ -371,31 +371,31 @@ local function drawShip(size,align,x,y,char) x,y=x+stepX,y+stepY end end - + local function setStatusLine(lineNum,text) doScreenColor() local pad=math.floor((termWidth-#text)/2) term.setCursorPos(1,16+lineNum) term.write((" "):rep(pad)..text..(" "):rep(termWidth-#text-pad)) end - - + + doScreenColor() term.clear() - + drawGrid(2,2,myGrid) - + setStatusLine(1,"Started game with "..opponent.." at computer #"..(opponentID or "nil")) - + local function getShipBounds(ship) return { minX=ship.pos[1], minY=ship.pos[2], maxX=ship.pos[1]+(ship.dir=="h" and ship.size-1 or 0), maxY=ship.pos[2]+(ship.dir=="v" and ship.size-1 or 0) - } + } end - + local function getPointBounds(x,y) return { minX=x, @@ -404,20 +404,20 @@ local function getPointBounds(x,y) maxY=y, } end - + local function boundsIntersect(boundsA,boundsB) return not ( boundsA.minX>boundsB.maxX or boundsA.maxXboundsB.maxY or boundsA.maxY="0" and p1<="9" then local t=string.byte(p1)-string.byte("0") if t==0 then t=10 end - moveTargetIndicator(t,targetY) + moveTargetIndicator(t,targetY) end elseif e=="key" then if p1==keys.enter or p1==keys.space and targetX and targetY then @@ -736,7 +736,7 @@ local function runGame() moveTargetIndicator(math.max(targetX-1,1),targetY) elseif p1==keys.right then moveTargetIndicator(math.min(targetX+1,10),targetY) - end + end end end --shot sent, wait for my turn to resolve (top coroutine will switch turns and draw the hit to the grid) @@ -746,12 +746,12 @@ local function runGame() end end end - + local gameRoutine=coroutine.create(runGame) --if advanced terminal, default focus to chat, can play with mouse local inChat=term.isColor() local savedCursorPos={7,19} - + --redirect just to block scroll local redir={} for k,v in pairs(originalTerm) do @@ -762,12 +762,12 @@ for k,v in pairs(originalTerm) do end end originalTerm = term.redirect(redir) - + --run the game routine once coroutine.resume(gameRoutine) --hide cursor term.setCursorBlink(false) - + while true do local e,p1,p2,p3,p4,p5=os.pullEventRaw() if e=="terminate" then @@ -791,7 +791,7 @@ while true do opponentReady=true os.queueEvent("kickcoroutine") elseif cmd=="cointoss" then - myTurn=args=="true" + myTurn=args=="true" if myTurn then setStatusLine(2,"Your turn, take your shot!") else @@ -807,11 +807,11 @@ while true do local tile=myGrid[tx][ty] local shot=makeShot(tx,ty,myGrid) rednet.send(opponentID,"bs result "..(shot[3] and "hit" or "miss")) - drawTile(2+tx,3+ty,tile) + drawTile(2+tx,3+ty,tile) myTurn=true os.queueEvent("kickcoroutine") displayGameHelp() - setStatusLine(1,opponent.." fired at "..toGridRef(tx,ty).." and "..(shot[3] and "hit" or "missed")) + setStatusLine(1,opponent.." fired at "..toGridRef(tx,ty).." and "..(shot[3] and "hit" or "missed")) setStatusLine(2,"Your turn, take your shot!") end elseif cmd=="sink" then @@ -838,7 +838,7 @@ while true do setStatusLine(2,"Waiting for opponent...") os.queueEvent("kickcoroutine") end - + elseif cmd=="win" then --we won! setStatusLine(3,"You won the game! Congratulations!") @@ -852,24 +852,24 @@ while true do print("game coroutine crashed with the following error: "..err) quit() end - + if coroutine.status(gameRoutine)=="dead" then --game over break end end - + end - + term.setCursorPos(1,19) term.clearLine() term.write(" Press any key to continue...") os.pullEvent("key") --if a char event was queued following the key event, this will eat it os.sleep(0) - + term.setTextColor(colors.white) term.setBackgroundColor(colors.black) term.clear() quit() --- \ No newline at end of file +-- diff --git a/src/main/resources/data/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua b/src/main/resources/data/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua index b8de7b147..7ec78c299 100644 --- a/src/main/resources/data/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua +++ b/src/main/resources/data/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua @@ -1,8 +1,8 @@ --- +-- -- Lua IDE -- Made by GravityScore --- +-- -- -------- Variables @@ -44,7 +44,7 @@ local function isAdvanced() return term.isColor and term.isColor() end local function modRead(properties) local w, h = term.getSize() - local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil, + local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil, liveUpdates = nil, exitOnKey = nil} if not properties then properties = {} end for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end @@ -58,7 +58,7 @@ local function modRead(properties) local function redraw(repl) local scroll = 0 - if properties.visibleLength and sx + pos > properties.visibleLength + 1 then + if properties.visibleLength and sx + pos > properties.visibleLength + 1 then scroll = (sx + pos) - (properties.visibleLength + 1) end @@ -133,9 +133,9 @@ local function modRead(properties) elseif (but == keys.up or but == keys.down) and properties.history then redraw(" ") if but == keys.up then - if historyPos == nil and #properties.history > 0 then + if historyPos == nil and #properties.history > 0 then historyPos = #properties.history - elseif historyPos > 1 then + elseif historyPos > 1 then historyPos = historyPos - 1 end elseif but == keys.down then @@ -173,9 +173,9 @@ local function modRead(properties) elseif but == keys["end"] then pos = line:len() redraw() - elseif properties.exitOnKey then - if but == properties.exitOnKey or (properties.exitOnKey == "control" and - (but == 29 or but == 157)) then + elseif properties.exitOnKey then + if but == properties.exitOnKey or (properties.exitOnKey == "control" and + (but == 29 or but == 157)) then term.setCursorBlink(false) return nil end @@ -296,7 +296,7 @@ end local function centerRead(wid, begt) local function liveUpdate(line, e, but, x, y, p4, p5) - if isAdvanced() and e == "mouse_click" and x >= w/2 - wid/2 and x <= w/2 - wid/2 + 10 + if isAdvanced() and e == "mouse_click" and x >= w/2 - wid/2 and x <= w/2 - wid/2 + 10 and y >= 13 and y <= 15 then return true, "" end @@ -707,7 +707,7 @@ languages.brainfuck.mapLoops = function(code) loopLocations[loc] = true elseif let == "]" then local found = false - for i = loc, 1, -1 do + for i = loc, 1, -1 do if loopLocations[i] == true then loopLocations[i] = loc found = true @@ -877,7 +877,7 @@ local function run(path, lines, useArgs) local s = centerRead(w - 13, fs.getName(path) .. " ") for m in string.gmatch(s, "[^ \t]+") do ar[#ar + 1] = m:gsub("^%s*(.-)%s*$", "%1") end end - + saveFile(path, lines) term.setCursorBlink(false) term.setBackgroundColor(colors.black) @@ -949,7 +949,7 @@ local function run(path, lines, useArgs) term.setCursorPos(5, 14) term.write(b) end - + local opt = prompt({{"Error Help", w/2 - 15, 17}, {"Go To Line", w/2 + 2, 17}}, "horizontal") if opt == "Error Help" then @@ -1459,7 +1459,7 @@ end local function writeHighlighted(line) if curLanguage == languages.lua then - while line:len() > 0 do + while line:len() > 0 do line = attemptToHighlight(line, "^%-%-%[%[.-%]%]", colors[theme.comment]) or attemptToHighlight(line, "^%-%-.*", colors[theme.comment]) or attemptToHighlight(line, "^\".*[^\\]\"", colors[theme.string]) or @@ -1491,7 +1491,7 @@ local function draw() for i = 1, edh do local a = lines[scrolly + i] if a then - local ln = string.rep(" ", offx - 1 - tostring(scrolly + i):len()) .. tostring(scrolly + i) + local ln = string.rep(" ", offx - 1 - tostring(scrolly + i):len()) .. tostring(scrolly + i) local l = a:sub(scrollx + 1, edw + scrollx + 1) ln = ln .. ":" @@ -1541,7 +1541,7 @@ local function drawLine(...) for _, ly in pairs(ls) do local a = lines[ly] if a then - local ln = string.rep(" ", offx - 1 - tostring(ly):len()) .. tostring(ly) + local ln = string.rep(" ", offx - 1 - tostring(ly):len()) .. tostring(ly) local l = a:sub(scrollx + 1, edw + scrollx + 1) ln = ln .. ":" @@ -1651,7 +1651,7 @@ local function edit(path) draw() term.setCursorPos(x + offx, y + offy) term.setCursorBlink(true) - + -- Main loop local tid = os.startTimer(3) while true do @@ -1692,8 +1692,8 @@ local function edit(path) if f then table.insert(lines, y + 1, string.rep(" ", spaces + 2)) if not f:find("else", 1, true) and not f:find("elseif", 1, true) then - table.insert(lines, y + 2, string.rep(" ", spaces) .. - (f:find("repeat", 1, true) and "until " or f:find("{", 1, true) and "}" or + table.insert(lines, y + 2, string.rep(" ", spaces) .. + (f:find("repeat", 1, true) and "until " or f:find("{", 1, true) and "}" or "end")) end x, y = spaces + 3, y + 1 @@ -1771,7 +1771,7 @@ local function edit(path) x = math.min(lines[y]:len() + 1, x) cursorLoc(x, y, true) end - elseif e == "char" and allowEditorEvent and (displayCode and true or + elseif e == "char" and allowEditorEvent and (displayCode and true or y + scrolly - 1 == liveErr.line) then local shouldIgnore = false for k, v in pairs(liveCompletions) do @@ -2083,7 +2083,7 @@ local function changeTheme() sleep(1.6) return "menu" end - + term.write("LuaIDE - Could Not Load Theme!") fs.delete("/.LuaIDE_temp_theme_file") sleep(1.6) @@ -2100,7 +2100,7 @@ local function settings() title("LuaIDE - Settings") local opt = prompt({{"Change Theme", w/2 - 17, 8}, {"Return to Menu", w/2 - 19, 13}, - --[[{"Check for Updates", w/2 + 2, 8},]] {"Exit IDE", w/2 + 2, 13, bg = colors[theme.err], + --[[{"Check for Updates", w/2 + 2, 8},]] {"Exit IDE", w/2 + 2, 13, bg = colors[theme.err], highlight = colors[theme.errHighlight]}}, "vertical", true) if opt == "Change Theme" then return changeTheme() -- elseif opt == "Check for Updates" then return update() @@ -2189,7 +2189,7 @@ if err and not err:find("Terminated") then term.write("Please report this error to") term.setCursorPos(6, cy + 3) term.write("GravityScore! ") - + term.setBackgroundColor(colors[theme.background]) if isAdvanced() then centerPrint("Click to Exit...", h - 1) else centerPrint("Press Any Key to Exit...", h - 1) end diff --git a/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze2d.lua b/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze2d.lua index ccc85fb29..be942df95 100644 --- a/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze2d.lua +++ b/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze2d.lua @@ -1,6 +1,6 @@ --[[ Project info: - + Name: Maze Creator: Jesusthekiller Language: Lua (CC) @@ -24,7 +24,7 @@ --[[ LICENSE: - + Maze Copyright (c) 2013 Jesusthekiller @@ -73,7 +73,7 @@ repeat cwrite("Enter maze size (5-99):") size = read() - + size = tonumber(size) if not size then size = 0 @@ -82,18 +82,18 @@ until size > 4 and size < 100 -- The generate local function mazeGen(mx, my) - + --[[ Format: - + maze.x.y.(1/2/3/4) = true/false - + 1 - top 2 - bottom 3 - right 4 - left ]]-- - + local maze = {} for i = 1, mx do maze[i] = {} @@ -116,26 +116,26 @@ local function mazeGen(mx, my) local intact = {} local x = curr.x local y = curr.y - + if x - 1 >= 1 and maze[x-1][y][1] and maze[x-1][y][2] and maze[x-1][y][3] and maze[x-1][y][4] then -- Check for full cells intact[#intact+1] = {x-1, y, 1} end - + if x + 1 <= mx and maze[x+1][y][1] and maze[x+1][y][2] and maze[x+1][y][3] and maze[x+1][y][4] then intact[#intact+1] = {x+1, y, 2} end - + if y + 1 <= my and maze[x][y+1][1] and maze[x][y+1][2] and maze[x][y+1][3] and maze[x][y+1][4] then intact[#intact+1] = {x, y+1, 3} end - + if y - 1 >= 1 and maze[x][y-1][1] and maze[x][y-1][2] and maze[x][y-1][3] and maze[x][y-1][4] then intact[#intact+1] = {x, y-1, 4} end - + if #intact > 0 then local i = math.random(1, #intact) -- Choose random - + if intact[i][3] == 1 then -- Set intact's attached wall to false maze[intact[i][1]][intact[i][2]][2] = false elseif intact[i][3] == 2 then @@ -145,11 +145,11 @@ local function mazeGen(mx, my) elseif intact[i][3] == 4 then maze[intact[i][1]][intact[i][2]][3] = false end - + maze[x][y][intact[i][3]] = false -- Set attached wall to false - + vis = vis + 1 -- Increase vis - + stack[#stack+1] = intact[i] -- Add to stack else local tmp = table.remove(stack) -- Get last cell @@ -157,7 +157,7 @@ local function mazeGen(mx, my) curr.y = tmp[2] end end - + return maze end @@ -177,7 +177,7 @@ local tab = {} for x = 1, size * 2 + 1 do tab[x] = {} - + for y = 1, size * 2 + 1 do if x % 2 == 0 and y % 2 == 0 then -- Fill cells (empty) tab[x][y] = false @@ -201,7 +201,7 @@ repeat -- Print map term.setBackgroundColor(colors.white) term.clear() - + if posx == 2 and posy == 2 then term.setCursorPos(1, 1) term.setTextColor(colors.black) @@ -211,27 +211,27 @@ repeat print("Goal: Step on # (It's on bottom right corner)") print("\nGood Luck!") end - + --[[ term.setTextColor(colors.black) term.setCursorPos(1, 19) write("X: "..posx.." Y: "..posy) ]] - + for x, tV in ipairs(tab) do -- Print the map for y, v in ipairs(tV) do if offsety+y > 20 then break end - + term.setCursorPos(offsetx+x, offsety+y) - + if v then term.setBackgroundColor(colors.black) else term.setBackgroundColor(colors.white) end - + if offsety+y < 20 and offsety+y > 0 and offsetx+x < 52 and offsetx+x > 0 then if x == size*2 and y == size*2 then if term.isColor() then @@ -243,51 +243,51 @@ repeat end end end - + if offsetx+x > 51 then break end - end - + end + term.setCursorPos(51/2, 19/2) term.setBackgroundColor(colors.white) - + if term.isColor() then term.setTextColor(colors.red) else term.setTextColor(colors.black) end - + write("X") - + -- Wait for key - + local e, k = os.pullEvent("char") - + if k == "a" and (not tab[posx-1][posy]) then posx = posx - 1 offsetx = offsetx + 1 end - + if k == "d" and (not tab[posx+1][posy]) then posx = posx + 1 offsetx = offsetx - 1 end - + if k == "w" and (not tab[posx][posy-1]) then posy = posy - 1 offsety = offsety + 1 end - + if k == "s" and (not tab[posx][posy+1]) then posy = posy + 1 offsety = offsety - 1 end - + if k == "q" then break end - + if k == "r" then posx = 2 posy = 2 @@ -324,4 +324,4 @@ term.setBackgroundColor(colors.black) term.setTextColor(colors.white) term.clear() term.setCursorPos(1, 1) -cprint(" Maze by JTK. Thanks for playing!") \ No newline at end of file +cprint(" Maze by JTK. Thanks for playing!") diff --git a/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze3d.lua b/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze3d.lua index 85343aeab..a8a04ee85 100644 --- a/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze3d.lua +++ b/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze3d.lua @@ -1,6 +1,6 @@ --[[ Project info: - + Name: Maze 3D Creator: Jesusthekiller Language: Lua (CC) @@ -28,7 +28,7 @@ --[[ LICENSE: - + Maze 3D Copyright (c) 2013 Jesusthekiller @@ -78,7 +78,7 @@ repeat cwrite("Enter maze size (5-99):") size = read() - + size = tonumber(size) if not size then size = 0 @@ -87,18 +87,18 @@ until size > 4 and size < 100 -- The generate local function mazeGen(mx, my) - + --[[ Format: - + maze.x.y.(1/2/3/4) = true/false - + 1 - top 2 - bottom 3 - right 4 - left ]]-- - + local maze = {} for i = 1, mx do maze[i] = {} @@ -121,26 +121,26 @@ local function mazeGen(mx, my) local intact = {} local x = curr.x local y = curr.y - + if x - 1 >= 1 and maze[x-1][y][1] and maze[x-1][y][2] and maze[x-1][y][3] and maze[x-1][y][4] then -- Check for full cells intact[#intact+1] = {x-1, y, 1} end - + if x + 1 <= mx and maze[x+1][y][1] and maze[x+1][y][2] and maze[x+1][y][3] and maze[x+1][y][4] then intact[#intact+1] = {x+1, y, 2} end - + if y + 1 <= my and maze[x][y+1][1] and maze[x][y+1][2] and maze[x][y+1][3] and maze[x][y+1][4] then intact[#intact+1] = {x, y+1, 3} end - + if y - 1 >= 1 and maze[x][y-1][1] and maze[x][y-1][2] and maze[x][y-1][3] and maze[x][y-1][4] then intact[#intact+1] = {x, y-1, 4} end - + if #intact > 0 then local i = math.random(1, #intact) -- Choose random - + if intact[i][3] == 1 then -- Set intact's attached wall to false maze[intact[i][1]][intact[i][2]][2] = false elseif intact[i][3] == 2 then @@ -150,11 +150,11 @@ local function mazeGen(mx, my) elseif intact[i][3] == 4 then maze[intact[i][1]][intact[i][2]][3] = false end - + maze[x][y][intact[i][3]] = false -- Set attached wall to false - + vis = vis + 1 -- Increase vis - + stack[#stack+1] = intact[i] -- Add to stack else local tmp = table.remove(stack) -- Get last cell @@ -162,7 +162,7 @@ local function mazeGen(mx, my) curr.y = tmp[2] end end - + return maze end @@ -180,7 +180,7 @@ local tab = {} for x = 1, size * 2 + 1 do tab[x] = {} - + for y = 1, size * 2 + 1 do if x % 2 == 0 and y % 2 == 0 then -- Fill cells (empty) tab[x][y] = " " @@ -263,13 +263,13 @@ if redirect then print("redirect API found, using buffer") else local pe=printError - rawset(_G,"printError",error) + rawset(_G,"printError",error) local ok, err=pcall(os.loadAPI,"redirect") if not ok then print("trying "..shell.dir().."/redirect") ok,err=pcall(os.loadAPI,shell.dir().."/redirect") end - if ok then + if ok then print("Loaded redirect API, using buffer") buffer=redirect.createRedirectBuffer() loadedAPI=true @@ -277,7 +277,7 @@ else print("redirect API not found or could not be loaded, drawing directly; this may cause flickering.") end rawset(_G,"printError",pe) -end +end local colorSchemes = { {0,8}, --white+gray @@ -338,10 +338,10 @@ local function cast(cx,cy,angle) end local wall=map[y]:sub(x,x) if wall~=" " then - + return colorSchemes[tonumber(wall)][isX and 1 or 2], hitD end - end + end end local w,h=term.getSize() @@ -370,7 +370,7 @@ for x=1,w do t.angle=math.atan2(x-centerX,screenDist) t.dist=((x-centerX)^2+screenDist^2)^.5/screenDist end - + local function redraw() local oldTerm if buffer.isBuffer then @@ -411,15 +411,15 @@ local function clampCollision(x,y,radius) --I am. Complete fail, do nothing. return x,y end - + --ok, check the neighbors. local right=math.floor(x+radius)>gx local left=math.floor(x-radius)gy - + local pushed=false - + if right and map[gy]:sub(gx+1,gx+1)~=" " then --push left pushed=true @@ -429,7 +429,7 @@ local function clampCollision(x,y,radius) pushed=true x=gx+radius end - + if front and map[gy-1]:sub(gx,gx)~=" " then --push back pushed=true @@ -442,7 +442,7 @@ local function clampCollision(x,y,radius) y=gy+1-radius end - + --if I wasn't pushed out on any side, I might be hitting a corner if not pushed then --square rad @@ -482,7 +482,7 @@ local function clampCollision(x,y,radius) x=x+pushx y=y+pushy end - + return x,y end @@ -533,7 +533,7 @@ while true do redraw() dirty=false end - + local e={os.pullEvent()} if e[1]=="key" then if e[2]==keys.left then @@ -565,7 +565,7 @@ while true do dir=startdir dirty=true end - + if px >= mapW-1 and py >= mapH-1 then win = true break diff --git a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/get.lua b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/get.lua index 6c95fbd6d..a8d7901d3 100644 --- a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/get.lua +++ b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/get.lua @@ -23,4 +23,4 @@ if fs.exists(args[1]) then else print("Client rejected file!") end -end \ No newline at end of file +end diff --git a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua index a76aba8d6..df62694fc 100644 --- a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua +++ b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua @@ -718,4 +718,4 @@ elseif #args >= 1 then --either no server running or we are the local shell on t else print("Usage: nsh [resume]") print(" nsh host [remote [local [name]]]") -end \ No newline at end of file +end diff --git a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/put.lua b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/put.lua index 23e6a2e3c..a31fe0be9 100644 --- a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/put.lua +++ b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/put.lua @@ -32,4 +32,4 @@ if message ~= "fileNotFound" then else print("Empty file not written!") end -end \ No newline at end of file +end diff --git a/src/main/resources/data/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua b/src/main/resources/data/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua index 8fdfbbf85..88e394b1e 100644 --- a/src/main/resources/data/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua +++ b/src/main/resources/data/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua @@ -124,7 +124,7 @@ end local function getAIMove() -- make it seem like the computer actually has to think about its move sleep(0.8) - + -- check if AI can win and return the 3rd tile to create a win, if it cannot, check for a human attempt at winning and stop it, if there is none, return a random return (search(currentPlayer) or search(opposites[currentPlayer])) or math.random(1,9) end @@ -177,7 +177,7 @@ local function modread( _mask, _history, _limit ) redraw(' ') if event[2] == keys.up then if not historyPos then - historyPos = #_history + historyPos = #_history elseif historyPos > 1 then historyPos = historyPos - 1 end @@ -308,14 +308,14 @@ local function render() writeAt('+'..string.rep('-', sw-2)..'+', 1, 3) writeAt('+'..string.rep('-', sw-2)..'+', 1, sh-2) writeAt('+'..string.rep('-', sw-2)..'+', 1, sh) - + if term.isColor and term.isColor() then term.setCursorPos(sw, 1) term.setBackgroundColor(colors.red) term.setTextColor(colors.black) writeWithFormat('X') end - + -- set our colours term.setBackgroundColor(colors.white) term.setTextColor(colors.black) @@ -359,7 +359,7 @@ local function render() writeAt((board[i + 6] == 'x' and '/\\' or '\\/'), 18+((i-1)*7), 14) end end - + -- draw the current player term.setCursorPos(3, sh - 3) if not winner then @@ -441,4 +441,4 @@ cwriteWithFormat('&4Thank you for playing CCTicTacToe v1.0', 1) cwriteWithFormat('&4By &8TheOriginal&3BIT\n', 2) -- restore the default terminal object -term.redirect( oldTermObj ) \ No newline at end of file +term.redirect( oldTermObj ) diff --git a/src/main/resources/data/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua b/src/main/resources/data/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua index bf126850d..dc1672f70 100644 --- a/src/main/resources/data/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua +++ b/src/main/resources/data/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua @@ -22,7 +22,7 @@ while not bFinished do break end - -- Get this every frame incase the monitor resizes + -- Get this every frame incase the monitor resizes local w,h = term.getSize() local startX = math.floor( (w - 65) / 2 ) local startY = math.floor( (h - 14) / 2 ) diff --git a/src/main/resources/data/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua b/src/main/resources/data/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua index ee7e8a8f8..c43fd6d4a 100644 --- a/src/main/resources/data/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua +++ b/src/main/resources/data/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua @@ -1 +1 @@ -print( "\"talk\" was removed in ComputerCraft 1.6, use the builtin \"chat\" program instead!" ) \ No newline at end of file +print( "\"talk\" was removed in ComputerCraft 1.6, use the builtin \"chat\" program instead!" ) diff --git a/src/main/resources/data/computercraft/lua/treasure/fredthead/protector/protector.lua b/src/main/resources/data/computercraft/lua/treasure/fredthead/protector/protector.lua index 255c238d1..bd88cee1d 100644 --- a/src/main/resources/data/computercraft/lua/treasure/fredthead/protector/protector.lua +++ b/src/main/resources/data/computercraft/lua/treasure/fredthead/protector/protector.lua @@ -27,11 +27,11 @@ function initVariables() human6x = 85 human6y = 18 human1 = true - human2 = true - human3 = true - human4 = true - human5 = true - human6 = true + human2 = true + human3 = true + human4 = true + human5 = true + human6 = true human1Abducted=false human2Abducted=false human3Abducted=false @@ -245,7 +245,7 @@ function printScore() end function rewriteScores() - if newScore > score1 then + if newScore > score1 then name5=name4 score5=score4 name4=name3 score4=score3 name3=name2 score3=score2 @@ -264,7 +264,7 @@ function rewriteScores() name5=name4 score5=score4 name4=newName score4=newScore elseif newScore > score5 then - name5=newName score5=newScore + name5=newName score5=newScore end local highScoreTable = {{name1, score1}, {name2,score2}, {name3,score3}, {name4,score4}, {name5,score5}} local newHighScoreStr = textutils.serialize(highScoreTable) @@ -289,7 +289,7 @@ function newHighScoreObtained() newNameStr=newNameStr..p1 newNameStrLen=newNameStrLen+1 printCent(14,newNameStr.." ") - + elseif event=="key" and p1 == 14 and newNameStrLen>0 then newNameStr=string.sub(newNameStr,1,string.len(newNameStr)-1) newNameStrLen=newNameStrLen-1 @@ -303,9 +303,9 @@ function newHighScoreObtained() printScore() end end - - + + end function highScore() @@ -327,8 +327,8 @@ function highScore() newHighScoreObtained() end printScore() - - + + end @@ -351,24 +351,24 @@ function gameOver(gameOverMsg) running=false sleep(1.5) highScore()-- new - --playAgain + --playAgain end function playAgain() sleep(1) printCent(12,"Play again (Y or N)") - + while true do local event,p1,p2,p3 = os.pullEvent() if event=="char" then - if string.lower(p1)=="y" then + if string.lower(p1)=="y" then runGame() - elseif string.lower(p1)=="n" then + elseif string.lower(p1)=="n" then os.shutdown() end end end - + end function killPlayer() @@ -378,7 +378,7 @@ function killPlayer() moveDown=false delShip(shipYPos) lives=lives-1 - if lives==0 then + if lives==0 then gameOver("OUT OF LIVES") end killedState=true @@ -438,7 +438,7 @@ function right() end function up() - if shipYPos > 2 then + if shipYPos > 2 then delShip(shipYPos) shipYPos=shipYPos-1 checkShipCollision() @@ -449,7 +449,7 @@ function up() end function down() - if shipYPos<17 then + if shipYPos<17 then delShip(shipYPos) shipYPos=shipYPos+1 checkShipCollision() @@ -480,7 +480,7 @@ function checkShipCollision() if human3x >=24 and human3x <= 26 then human3=false humanHitRoutine() - end + end elseif human4==true and human4y==shipYPos then if human4x >=24 and human4x <= 26 then human4=false @@ -495,7 +495,7 @@ function checkShipCollision() if human6x >=24 and human6x <= 26 then human6=false humanHitRoutine() - end + end end end end @@ -551,7 +551,7 @@ function alienDown() alien1Abduct=true alien1Carry=true alien1Step=17 - end + end end end @@ -564,74 +564,74 @@ function alienRoutine() end alien1Abduct=false alien1Carry=false - if humansLeft==0 then + if humansLeft==0 then gameOver("NO HUMANS LEFT") end - + end function alienUp() if alien1==true and alien1Abduct==true then - if alien1x+1 == human1x then + if alien1x+1 == human1x then human1Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human1y=math.floor(alien1Step)+1 human1x=alien1x+1 - if human1y<=2 then + if human1y<=2 then alienRoutine() human1=false end - elseif alien1x+1 == human2x then + elseif alien1x+1 == human2x then human2Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human2y=math.floor(alien1Step)+1 human2x=alien1x+1 - if human2y<=2 then + if human2y<=2 then alienRoutine() human2=false end - elseif alien1x+1 == human3x then + elseif alien1x+1 == human3x then human3Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human3y=math.floor(alien1Step)+1 human3x=alien1x+1 - if human3y<=2 then + if human3y<=2 then alienRoutine() human3=false end - elseif alien1x+1 == human4x then + elseif alien1x+1 == human4x then human4Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human4y=math.floor(alien1Step)+1 human4x=alien1x+1 - if human4y<=2 then + if human4y<=2 then alienRoutine() human4=false end - elseif alien1x+1 == human5x then + elseif alien1x+1 == human5x then human5Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human5y=math.floor(alien1Step)+1 human5x=alien1x+1 - if human5y<=2 then + if human5y<=2 then alienRoutine() human5=false end - elseif alien1x+1 == human6x then + elseif alien1x+1 == human6x then human6Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human6y=math.floor(alien1Step)+1 human6x=alien1x+1 - if human6y<=2 then + if human6y<=2 then alienRoutine() human6=false - end + end end end if alien1==false then alienGen() end @@ -645,7 +645,7 @@ function keyPress() -- 200 UP, 208 DOWN, 203 LEFT, 205 RIGHT, 57 SPACE, 16 Q moveDown=true moveUp=false elseif pressedKey==203 or pressedKey == 30 then -- left - moveLeft=true + moveLeft=true moveRight=false elseif pressedKey==205 or pressedKey == 32 then -- right moveRight=true @@ -654,7 +654,7 @@ function keyPress() -- 200 UP, 208 DOWN, 203 LEFT, 205 RIGHT, 57 SPACE, 16 Q if bulletState==false then bulletYPos=shipYPos bulletState=true - if shipFacingRight==true then + if shipFacingRight==true then bulletXPos=shipXPos+3 bulletGoingRight=true else @@ -665,13 +665,13 @@ function keyPress() -- 200 UP, 208 DOWN, 203 LEFT, 205 RIGHT, 57 SPACE, 16 Q elseif pressedKey==25 then -- q (use 25 if p for quit) gameOver("YOU QUIT") end - + --term.setCursorPos(30,1) --write(pressedKey.." ") end function removeBullet() - if bulletGoingRight==true then + if bulletGoingRight==true then bulletXPos = 60 else bulletXPos = -10 @@ -691,7 +691,7 @@ end function humanHitRoutine() score=score-50 humansLeft=humansLeft-1 - if humansLeft==0 then + if humansLeft==0 then gameOver("NO HUMANS LEFT") end if alien1Carry==true then alien1Carry=false end @@ -699,9 +699,9 @@ end function checkBulletCollision() - if alien1 == true and bulletYPos == alien1y then - if bulletXPos >= alien1x and bulletXPos <= alien1x + 3 then - alien1Hit() + if alien1 == true and bulletYPos == alien1y then + if bulletXPos >= alien1x and bulletXPos <= alien1x + 3 then + alien1Hit() end end if human1 == true and bulletYPos == human1y and bulletXPos == human1x then human1=false humanHitRoutine() end @@ -737,15 +737,15 @@ end function gameControl() gameTimer=os.startTimer(0.1) - + while running do local event,p1,p2,p3 = os.pullEvent() if score<0 then score=0 end term.setCursorPos(1,1) term.setBackgroundColour(colours.yellow) write(string.rep(" ",w)) - - + + term.setTextColour(colours.red) term.setCursorPos(5,1) write("Score: "..score.." ") @@ -753,15 +753,15 @@ function gameControl() write("Humans Left: "..humansLeft.." ") term.setCursorPos(40,1) write("Lives: "..lives.." ") - + term.setBackgroundColour(colours.black) term.setTextColour(colours.white) - + local newStepValue = (score+0.1)/1000 if newStepValue > stepValue then stepValue= newStepValue end if stepValue>0.4 then stepValue=0.4 end - - + + --[[DEBUG term.setCursorPos(2,2) write("human1x "..human1x.." ") @@ -776,10 +776,10 @@ function gameControl() term.setCursorPos(2,7) write("human6x "..human6x.." ") ]]-- - - + + if event=="timer" and gameTimer == p1 then - if killedState==true then + if killedState==true then delShip(shipYPos) delHumans() dropHumans() @@ -800,15 +800,15 @@ function gameControl() else moveLeft=true moveRight=false - end + end killedDelay=0 end else - + --alienGen() drawShip(shipYPos) delAliens() - + delHumans() dropHumans() alienDown() @@ -817,7 +817,7 @@ function gameControl() drawHumans() drawBorder() end - + if bulletState==true then if bulletGoingRight==true then delBullet() @@ -839,7 +839,7 @@ function gameControl() end end end - + if moveLeft==true then left() end @@ -852,16 +852,16 @@ function gameControl() if moveDown==true then down() end - + gameTimer=os.startTimer(0.1) - - elseif event=="key" and killedState==false then + + elseif event=="key" and killedState==false then pressedKey=p1 keyPress() end - - end - + + end + end function runGame() @@ -875,7 +875,7 @@ end function pix(xCo,yCo,text,col) - if col== nil then term.setBackgroundColour(colours.black) + if col== nil then term.setBackgroundColour(colours.black) elseif col =="white" then term.setBackgroundColour(colours.white) elseif col =="green" then term.setBackgroundColour(colours.green) elseif col =="pink" then term.setBackgroundColour(colours.pink) @@ -977,7 +977,7 @@ function line2() pix(38,5," ","white") pix(40,5," ","white") pix(42,5," ","white") - + end function line3() @@ -1030,7 +1030,7 @@ function startScreen() term.setCursorPos(1,h) write(string.rep(" ",w)) local screenStage=0 - + screenTimer=os.startTimer(0.1) while true do local event,p1,p2,p3=os.pullEvent() @@ -1039,12 +1039,12 @@ function startScreen() clear() runGame() elseif event=="timer" and screenTimer == p1 then - + --term.setCursorPos(1,1) write("screenStage: "..screenStage.." ") - + term.setBackgroundColour(colours.black) term.setCursorPos(35,1) write("SPACE WHEN READY") - + if screenStage>0 and screenStage<0.5 then humanPixY = 18 drawHumanPix() @@ -1055,17 +1055,17 @@ function startScreen() alienPixY = -2 delAlienPix() alienPixY = -1 - drawAlienPix() + drawAlienPix() elseif screenStage>4 and screenStage<4.9 then alienPixY = -1 delAlienPix() alienPixY = 0 - drawAlienPix() + drawAlienPix() elseif screenStage>5 and screenStage<5.9 then alienPixY = 0 delAlienPix() alienPixY = 1 - drawAlienPix() + drawAlienPix() elseif screenStage>6 and screenStage<6.9 then alienPixY = 1 delAlienPix() @@ -1080,7 +1080,7 @@ function startScreen() alienPixY = 3 delAlienPix() alienPixY = 4 - drawAlienPix() + drawAlienPix() elseif screenStage>8 and screenStage<9.9 then alienPixY = 4 delAlienPix() @@ -1120,7 +1120,7 @@ function startScreen() pix(22,17," ","yellow") pix(22,18," ","yellow") humanPixY = 18 - drawHumanPix() + drawHumanPix() elseif screenStage>10.8 and screenStage<11 then pix(25,8," ","yellow") pix(24,9," ","yellow") @@ -1134,7 +1134,7 @@ function startScreen() pix(20,17," ","yellow") pix(20,18," ","yellow") humanPixY = 18 - drawHumanPix() + drawHumanPix() elseif screenStage>11.9 and screenStage<12 then pix(1,6," ","yellow") elseif screenStage>12 and screenStage<12.1 then @@ -1142,7 +1142,7 @@ function startScreen() pix(3,6," ","yellow") elseif screenStage>12.1 and screenStage<12.2 then pix(3,6," ") - pix(5,6," ","yellow") + pix(5,6," ","yellow") elseif screenStage>12.2 and screenStage<12.3 then pix(5,6," ") pix(7,6," ","yellow") @@ -1166,102 +1166,102 @@ function startScreen() end humanPixY=18 drawHumanPix() - elseif screenStage>13 and screenStage<13.1 then + elseif screenStage>13 and screenStage<13.1 then shipPixX= -16 drawShipPix() - elseif screenStage>13 and screenStage<13.1 then + elseif screenStage>13 and screenStage<13.1 then delShipPix() shipPixX= -15 - drawShipPix() - elseif screenStage>13.1 and screenStage<13.2 then + drawShipPix() + elseif screenStage>13.1 and screenStage<13.2 then delShipPix() shipPixX= -12 - drawShipPix() - elseif screenStage>13.2 and screenStage<13.3 then + drawShipPix() + elseif screenStage>13.2 and screenStage<13.3 then delShipPix() shipPixX= -9 drawShipPix() - elseif screenStage>13.2 and screenStage<13.3 then + elseif screenStage>13.2 and screenStage<13.3 then delShipPix() shipPixX= -6 drawShipPix() - elseif screenStage>13.3 and screenStage<13.4 then + elseif screenStage>13.3 and screenStage<13.4 then delShipPix() shipPixX= -3 drawShipPix() - elseif screenStage>13.4 and screenStage<13.5 then + elseif screenStage>13.4 and screenStage<13.5 then delShipPix() shipPixX= 0 drawShipPix() - elseif screenStage>13.6 and screenStage<13.7 then + elseif screenStage>13.6 and screenStage<13.7 then delShipPix() shipPixX= 3 drawShipPix() - elseif screenStage>13.8 and screenStage<13.9 then + elseif screenStage>13.8 and screenStage<13.9 then delShipPix() shipPixX= 6 drawShipPix() - elseif screenStage>13.9 and screenStage<14 then + elseif screenStage>13.9 and screenStage<14 then delShipPix() shipPixX= 9 drawShipPix() - elseif screenStage>14.1 and screenStage<14.2 then + elseif screenStage>14.1 and screenStage<14.2 then delShipPix() shipPixX= 12 drawShipPix() - elseif screenStage>14.2 and screenStage<14.3 then + elseif screenStage>14.2 and screenStage<14.3 then delShipPix() shipPixX= 15 drawShipPix() - elseif screenStage>14.3 and screenStage<14.4 then + elseif screenStage>14.3 and screenStage<14.4 then delShipPix() shipPixX= 18 drawShipPix() - elseif screenStage>14.4 and screenStage<14.5 then + elseif screenStage>14.4 and screenStage<14.5 then delShipPix() shipPixX= 21 drawShipPix() - elseif screenStage>14.5 and screenStage<14.6 then + elseif screenStage>14.5 and screenStage<14.6 then delShipPix() shipPixX= 24 drawShipPix() - elseif screenStage>14.6 and screenStage<14.7 then + elseif screenStage>14.6 and screenStage<14.7 then delShipPix() shipPixX= 27 drawShipPix() - elseif screenStage>14.7 and screenStage<14.8 then + elseif screenStage>14.7 and screenStage<14.8 then delShipPix() shipPixX= 30 drawShipPix() - elseif screenStage>14.8 and screenStage<14.9 then + elseif screenStage>14.8 and screenStage<14.9 then delShipPix() shipPixX= 33 drawShipPix() - elseif screenStage>14.9 and screenStage<15 then + elseif screenStage>14.9 and screenStage<15 then delShipPix() shipPixX= 36 drawShipPix() - elseif screenStage>15 and screenStage<15.1 then + elseif screenStage>15 and screenStage<15.1 then delShipPix() shipPixX= 39 drawShipPix() - elseif screenStage>15.1 and screenStage<15.2 then + elseif screenStage>15.1 and screenStage<15.2 then delShipPix() shipPixX= 41 drawShipPix() - elseif screenStage>15.2 and screenStage<15.3 then + elseif screenStage>15.2 and screenStage<15.3 then delShipPix() shipPixX= 44 drawShipPix() - elseif screenStage>15.3 and screenStage<15.4 then + elseif screenStage>15.3 and screenStage<15.4 then delShipPix() shipPixX= 47 drawShipPix() - elseif screenStage>15.4 and screenStage<15.5 then + elseif screenStage>15.4 and screenStage<15.5 then delShipPix() shipPixX= 50 drawShipPix() - elseif screenStage>15.5 and screenStage<15.6 then + elseif screenStage>15.5 and screenStage<15.6 then delShipPix() elseif screenStage>16 and screenStage<16.9 then humanPixY=18 @@ -1284,7 +1284,7 @@ function startScreen() write("Fire when ready") elseif screenStage>22.1 and screenStage <27 then introHighScoreTable() - elseif screenStage>27 then + elseif screenStage>27 then term.setBackgroundColour(colours.black) for i = 2,h-1 do term.setCursorPos(1,i) @@ -1292,7 +1292,7 @@ function startScreen() end screenStage=0 end - + screenStage=screenStage+0.1 screenTimer=os.startTimer(0.025) end @@ -1308,4 +1308,4 @@ else term.setCursorPos(1,1) print("I'm sorry, Protector requires an Advanced Computer to run") print(" ") -end \ No newline at end of file +end diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua index 2aeaf4072..b75a5ca79 100644 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua +++ b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua @@ -89,7 +89,7 @@ local titleLevel = { local function parseValue(x, y, lchar) if tonumber(lchar, 16) then lchar = math.pow(2, tonumber(lchar,16)) - + if lchar == colours.blue then map[y][x] = 0 elseif lchar == colours.brown then @@ -146,7 +146,7 @@ local function loadMap(_sPath) goldMap = {} monks = {} goldCount = 0 - + local file = fs.open(_sPath, "r") local line = file:readLine() while line do @@ -279,14 +279,14 @@ local function resetMap() monk.x = monk.spawnX monk.y = monk.spawnY end - + for _,timer in pairs(blockTimers) do map[timer.y][timer.x] = 0 end blockTimers = {} plX = plspawnX plY = plspawnY - + moveTimer = -1 shootTimer = -1 spawnTimer = -1 @@ -320,27 +320,27 @@ end local function drawLevelList() local minLev = ((levelLot-1) * 10 + 1) local maxLev = minLev + math.min(10, #levelList - (levelLot-1) * 10) - 1 - + term.setCursorPos(7, 2) term.setBackgroundColour(colours.black) term.clearLine() for j = 1,49 do updateMap(j,2) end - + term.setBackgroundColour(colours.black) term.setTextColour(colours.white) term.setCursorPos(7, 2) local msg = "Levels "..minLev.." to "..maxLev.." of "..#levelList term.write(msg) - + term.setTextColour(colours.yellow) term.setCursorPos(4, 2) if levelLot > 1 then term.write("<-") - else term.write(" ") end - + else term.write(" ") end + term.setCursorPos(8 + #msg, 2) if maxLev < #levelList then term.write("->") else term.write(" ") end - + for i = 1,10 do term.setCursorPos(1, 3+i) for j = 1,49 do updateMap(j,3+i) end @@ -371,12 +371,12 @@ local function loadTitleScreen() if #map == 18 then break end end maxGoldCount = goldCount - + drawMap() term.setCursorPos(1,19) term.setBackgroundColour(colours.blue) term.clearLine() - + menIndex = 1 titleLoaded = true end @@ -384,22 +384,22 @@ end --Opens an in-game menu to display a series of options. local function inGameMenu(menuList) menIndex = 1 - + local squareTop,squareBottom = 4,6 + #menuList * 2 local squareSize = 0 for i=1,#menuList do squareSize = math.max(squareSize, #menuList[i] + 6) end - + for y=squareTop,squareBottom do term.setCursorPos(w/2 - squareSize/2, y) term.setBackgroundColour(colours.lightBlue) term.write(string.rep(" ", squareSize)) - + if y ~= squareTop and y ~= squareBottom then term.setCursorPos(w/2 - squareSize/2 + 1, y) term.setBackgroundColour(colours.black) term.write(string.rep(" ", squareSize - 2)) end - + if y ~= squareTop and y ~= squareBottom and y % 2 == 0 then local opt = menuList[(y - squareTop) / 2] term.setCursorPos(w/2 - #opt/2, y) @@ -407,7 +407,7 @@ local function inGameMenu(menuList) term.write(opt) end end - + local p1 = nil repeat for i=1,#menuList do @@ -426,20 +426,20 @@ local function inGameMenu(menuList) end end _,p1 = os.pullEvent("key") - + if p1 == keys.up and menIndex > 1 then menIndex = menIndex - 1 elseif p1 == keys.down and menIndex < #menuList then menIndex = menIndex + 1 end until p1 == keys.enter - + return menuList[menIndex] end --Checks to see if any given desired move is legal. Monks and players both use this. local function isLegalMove(initX,initY,finX,finY) - if finY < 1 or finY > #map or finX < 1 or finX > 49 then - return false + if finY < 1 or finY > #map or finX < 1 or finX > 49 then + return false end - + if map[finY][finX] ~= 0 and map[finY][finX] ~= '#' then --This reports 'self moves' as being illegal, but that's fine for _,monk in pairs(monks) do @@ -450,10 +450,10 @@ local function isLegalMove(initX,initY,finX,finY) then return true elseif finY == initY+1 and (map[finY][finX] == "H" or (map[finY][finX] == "h" and goldCount == 0) or (type(map[finY][finX]) == "number" and map[finY][finX] > 0) or map[finY][finX] == nil or - map[finY][finX] == "V" or map[finY][finX] == "-" or (map[finY][finX] == 'h' and goldCount ~= 0)) + map[finY][finX] == "V" or map[finY][finX] == "-" or (map[finY][finX] == 'h' and goldCount ~= 0)) then return true - elseif finX == initX-1 or finX == initX+1 then - return true + elseif finX == initX-1 or finX == initX+1 then + return true end end end @@ -461,12 +461,12 @@ end --Moves the player to a given step. local function movePlayer(x,y,ignoreLegal) if not ignoreLegal and not isLegalMove(plX,plY,x,y) then return false end - + local ox = plX local oy = plY plX = x plY = y - + updateMap(ox,oy) updateMap(x,y) if goldMap[y][x] == 1 then @@ -481,14 +481,14 @@ local function movePlayer(x,y,ignoreLegal) started = false nextLevel = true end - - pfalling = (y < #map and map[y][x] ~= '-' and map[y][x] ~= 'H' and not (map[y][x] == 'h' and goldCount == 0) + + pfalling = (y < #map and map[y][x] ~= '-' and map[y][x] ~= 'H' and not (map[y][x] == 'h' and goldCount == 0) and (map[y+1][x] == nil or map[y+1][x] == "V" or map[y+1][x] == 2 or map[y+1][x] == '-')) if (y < #map and map[y+1][x] == 'h' and goldCount ~= 0) then pfalling = true end for _,monk in pairs(monks) do if monk.x == plX and monk.y == plY + 1 then pfalling = false break end end - + return true end @@ -634,7 +634,7 @@ local function updateMonks() end end end - + if not (monk.trapped or monk.dead) then --Has the monk decided on moving left or right? If so we try to move him if monk.desX and not monk.falling then @@ -708,7 +708,7 @@ local function updateBlockTimer(tid) end local function shootBlock(x,y) - if y <= #map and map[y][x] == 0 and (map[y-1][x] == nil + if y <= #map and map[y][x] == 0 and (map[y-1][x] == nil or map[y-1][x] == 2 or (map[y-1][x] == 'h' and goldCount > 0)) then map[y][x] = 3 table.insert(blockTimers, {x = x; y = y; timer = os.startTimer(0.1);} ) @@ -718,14 +718,14 @@ end local function handleEvents() local id,p1,p2,p3 = os.pullEvent() - + if id == "key" then --Menu Handling if p1 == keys.up then if menIndex > 1 then menIndex = menIndex - 1 end elseif p1 == keys.down then - if inLevelSelect then - if menIndex < math.min(10, #levelList - (levelLot-1)*10) then + if inLevelSelect then + if menIndex < math.min(10, #levelList - (levelLot-1)*10) then menIndex = menIndex + 1 end elseif menIndex < #titleOptions then menIndex = menIndex + 1 end @@ -736,7 +736,7 @@ local function handleEvents() levelLot = levelLot + 1 drawLevelList() end - + --Game Handling if p1 == keys.a and moveTimer == -1 and spawnTimer == -1 then movePlayer(plX-1,plY) @@ -811,7 +811,7 @@ local function handleEvents() monk.trapped = nil monk.behaviour = "none" monk.justEscaped = true - + updateMap(monk.x, monk.y+1) drawMonk(monk) end @@ -859,12 +859,12 @@ local pallette = { { t = colours.black, b = colours.blue, s = " ", n = "Solid G local brushType = 1 local function getHexOf(colour) - if not colour or not tonumber(colour) then - return " " + if not colour or not tonumber(colour) then + return " " end local value = math.log(colour)/math.log(2) - if value > 9 then - value = hexnums[value] + if value > 9 then + value = hexnums[value] end return value end @@ -878,7 +878,7 @@ local function drawFooter() term.setCursorPos(w,i) term.write(" ") end - + term.setBackgroundColour(colours.black) term.setTextColour(colours.blue) term.setCursorPos(2,h) @@ -904,7 +904,7 @@ local function drawPallette(xpos,ypos) local top = ypos if xpos + xdim > w then left = left + (w - xpos - xdim) end if ypos + ydim > h then top = top + (h - ypos - ydim) end - + --There's no easy way to do this... so we draw it manually :( for i=0,4 do term.setCursorPos(left, top + i) @@ -913,25 +913,25 @@ local function drawPallette(xpos,ypos) if i == 0 or i == 4 then term.write("*-----*") else term.write("* *") end end - + for i=1,#pallette-1 do local ypl = 1 local xmv = i if i > 5 then ypl = 2 xmv = i - 5 end - + term.setCursorPos(left + xmv, top+ypl) term.setBackgroundColour(pallette[i].b) term.setTextColour(pallette[i].t) term.write(pallette[i].s) end - + term.setCursorPos(left + 1, top + 3) term.setBackgroundColour(colours.red) term.setTextColour(colours.black) term.write("ERASE") - + local _,button,x,y = os.pullEvent("mouse_click") - + if button == 1 then if y == top + 1 and x > left and x < left + 6 then brushType = x-left @@ -941,9 +941,9 @@ local function drawPallette(xpos,ypos) brushType = 11 end end - + for y = top,top+ydim do - for x = left,left+xdim do + for x = left,left+xdim do --Not sure why the -2 is necessary if map[y+drawOffsetY] then updateMap(x-2,y+drawOffsetY) end end @@ -955,7 +955,7 @@ end local function saveCurrentMap(path) local file = io.open(shell.resolve(".").."/levels/"..path, "w") if not file then return false end - + drawMap() drawFooter() local msg = "Saving.." @@ -968,7 +968,7 @@ local function saveCurrentMap(path) term.write(string.rep(" ", 18)) term.setCursorPos(w/2-9,6) term.setBackgroundColour(colours.lime) - + for y=1,#map do local xstr = "" for x=1,49 do @@ -1016,14 +1016,14 @@ local function runLevelEditor() end monks = {} end - + drawMap() drawFooter() - + while inLevelEditor do local id,button,x,y = os.pullEvent() if id == "mouse_click" or id == "mouse_drag" then - if button == 2 then + if button == 2 then drawPallette(x,y) elseif x > drawOffsetX and x <= 49 + drawOffsetX and y > drawOffsetY and y <= 18 + drawOffsetY then if pallette[brushType].v == "player" then @@ -1095,7 +1095,7 @@ local function runLevelSelect() if not titleLoaded then loadTitleScreen() monkTimer = os.startTimer(moveIntv * 1.5) - else + else drawMap() drawEndgameMap() term.setCursorPos(1,19) @@ -1103,11 +1103,11 @@ local function runLevelSelect() term.clearLine() end drawLevelList() - + menSel = "none" repeat handleEvents() - + term.setBackgroundColour(colours.black) term.setTextColour(colours.yellow) for i=1,10 do @@ -1131,23 +1131,23 @@ local function runTitle() term.write("Gold Runner") term.setCursorPos(16,4) term.write("By Nitrogen Fingers") - + term.setTextColour(colours.white) for i=1,#titleOptions do term.setCursorPos(19, 5 + (i*2)) term.write(titleOptions[i]) end - + term.setCursorPos(16, 7) term.setTextColour(colours.yellow) term.write("->") - + menSel = "none" monkTimer = os.startTimer(moveIntv * 1.5) - + repeat handleEvents() - + term.setBackgroundColour(colours.black) term.setTextColour(colours.yellow) for i=1,#titleOptions do @@ -1166,25 +1166,25 @@ local function playLevel() drawHUD() os.pullEvent("key") movePlayer(plX,plY,true) - + monkTimer = os.startTimer(moveIntv * 1.5) moveTimer = os.startTimer(moveIntv) shootTimer = -1 spawnTimer = -1 - + started = true while started do handleEvents() end - + if menSel == "Quit" or menSel == "Back to Title" or menSel == "Edit Level" then running = false return end menSel = "none" - + if nextLevel then - if currentLevel == #levelList then + if currentLevel == #levelList then started = false running = false break @@ -1198,12 +1198,12 @@ local function playLevel() else playerLives = playerLives-1 if playerLives > 0 then resetMap() - else - running = false + else + running = false end end end - + if nextLevel then local msg = "All levels defeated, Gold Runner!" term.setBackgroundColour(colours.black) @@ -1247,7 +1247,7 @@ while menSel ~= "Quit" do term.setCursorPos(1,19) term.setBackgroundColour(colours.blue) term.clearLine() - + term.setCursorPos(16,10) term.setBackgroundColour(colours.black) term.setTextColour(colours.white) @@ -1256,13 +1256,13 @@ while menSel ~= "Quit" do term.setCursorPos(17,11) term.setCursorBlink(true) local levelName = "" - + local id,p1 repeat id,p1 = os.pullEvent() if id == "key" and p1 == keys.backspace then levelName = string.sub(levelName, 1, #levelName - 1) - elseif id == "timer" and p1 == monkTimer then + elseif id == "timer" and p1 == monkTimer then updateMonks() monkTimer = os.startTimer(moveIntv * 2) elseif id == "char" and #levelName < 14 then @@ -1273,15 +1273,15 @@ while menSel ~= "Quit" do term.write(levelName..string.rep(" ",14 - #levelName)) term.setCursorPos(17 + #levelName ,11) until id == "key" and p1 == keys.enter and #levelName > 0 - + term.setCursorBlink(false) levelEditName = levelName runLevelEditor() - + if menSel == "Play Level" then currentLevel = nil levelList = fs.list(shell.resolve(".").."/levels") - for num,name in pairs(levelList) do + for num,name in pairs(levelList) do if name == levelName then currentLevel = num break @@ -1296,7 +1296,7 @@ while menSel ~= "Quit" do runLevelEditor() term.setBackgroundColour(colours.black) term.clear() - + if menSel == "Play Level" then menSel = "New Game" else diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua index be40631ff..89dc031cc 100644 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua +++ b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua @@ -1,7 +1,7 @@ --[[ 3D Print A printing program for use with NPaintPro - + By NitrogenFingers ]]-- @@ -30,7 +30,7 @@ local commandList = { ["DE"] = endPrint; } ---Splits a string according to a pattern into a table +--Splits a string according to a pattern into a table local function split(str, pattern) local t = { } local fpat = "(.-)" .. pattern @@ -56,11 +56,11 @@ local function respondToQuery() print("Listening for ACT/ID query") local id,key = rednet.receive() print("Received : "..key) - + if key == "$3DPRINT IDENTIFY" then print("Requested Identification") rednet.send(id, "$3DPRINT IDACK "..os.getComputerLabel()) - + elseif key == "$3DPRINT ACTIVATE" then print("Requested Activation") activeCommander = id @@ -76,10 +76,10 @@ local function performPrint() while operatingPrint do local id,msg = rednet.receive() print("Command : "..msg) - + if id == activeCommander and string.find(msg, "$PC") == 1 then local cmds = split(msg, " ") - + --It's a bit of a hack, but those are the 2 methods required for a refuel if turtle.getFuelLevel() == 0 and cmds[2] ~= "SS" and cmds[2] ~= "RF" then rednet.send(id, "$3DPRINT OOF") @@ -95,7 +95,7 @@ local function performPrint() commandList[cmds[2]][i](tonumber(cmds[3])) end end - + rednet.send(activeCommander, "$3DPRINT ACK") end end @@ -116,4 +116,4 @@ while true do respondToQuery() --Perform the print performPrint() -end \ No newline at end of file +end diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua index 8a029e83b..dac2bcc78 100644 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua +++ b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua @@ -25,7 +25,7 @@ function initializeBuffer(terminal) if not terminal.isColour() then error("Parameter does not represent an advanced computer.") end - + tw,th = terminal.getSize() backbuffer = { } for y=1,th do @@ -41,8 +41,8 @@ end function clearBuffer(colour) if not backbuffer then error("Back buffer not yet initialized!") - end - + end + for y=1,#backbuffer do backbuffer[y] = { } if colour then @@ -60,26 +60,26 @@ end function writeToBuffer(entity) if not backbuffer then error("Back buffer not yet initialized!") - end - + end + local image = nil if entity.type == "animation" then image = entity.frames[entity.currentFrame] else image = entity.image end - + for y=1,image.dimensions.height do for x=1,image.dimensions.width do if image[y][x] then local xpos,ypos = x,y if entity.mirror.x then xpos = image.dimensions.width - x + 1 end if entity.mirror.y then ypos = image.dimensions.height - y + 1 end - + --If the YPos doesn't exist, no need to loop through the rest of X! --Don't you love optimization? if not backbuffer[entity.y + ypos - 1] then break end - + backbuffer[entity.y + ypos - 1][entity.x + xpos - 1] = image[y][x] end end @@ -93,7 +93,7 @@ end function drawBuffer(terminal) if not backbuffer then error("Back buffer not yet initialized!") - end + end if not terminal then terminal = term end if not terminal.setCursorPos or not terminal.setBackgroundColour or not terminal.write then error("Parameter cannot be used to initialize the backbuffer.") @@ -101,7 +101,7 @@ function drawBuffer(terminal) if not terminal.isColour() then error("Parameter does not represent an advanced computer.") end - + for y=1,math.min(#backbuffer, th) do for x=1,tw do if backbuffer[y][x] then @@ -167,14 +167,14 @@ end ]]-- local function drawS(self) local image = self.image - + for y=1,image.dimensions.height do for x=1,image.dimensions.width do if image[y][x] then local xpos,ypos = x,y if self.mirror.x then xpos = image.dimensions.width - x + 1 end if self.mirror.y then ypos = image.dimensions.height - y + 1 end - + term.setBackgroundColour(image[y][x]) term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1) term.write(" ") @@ -198,7 +198,7 @@ local function drawA(self, frame) local xpos,ypos = x,y if self.mirror.x then xpos = image.dimensions.width - x + 1 end if self.mirror.y then ypos = image.dimensions.height - y + 1 end - + term.setBackgroundColour(image[y][x]) term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1) term.write(" ") @@ -259,16 +259,16 @@ local function drawBounds(entity, colour) local image = nil if entity.type == "animation" then image = entity.frames[entity.currentFrame] else image = entity.image end - + term.setBackgroundColour(colour) - + corners = { topleft = { x = entity.x + image.bounds.x - 1, y = entity.y + image.bounds.y - 1 }; topright = { x = entity.x + image.bounds.x + image.bounds.width - 2, y = entity.y + image.bounds.y - 1 }; botleft = { x = entity.x + image.bounds.x - 1, y = entity.y + image.bounds.y + image.bounds.height - 2 }; botright = { x = entity.x + image.bounds.x + image.bounds.width - 2, y = entity.y + image.bounds.y + image.bounds.height - 2 }; } - + term.setCursorPos(corners.topleft.x, corners.topleft.y) term.write(" ") term.setCursorPos(corners.topright.x, corners.topright.y) @@ -308,7 +308,7 @@ end local function rCollidesWith(self, other) --First we construct the rectangles local img1C, img2C = createRectangle(self), createRectangle(other) - + --We then determine the "relative position" , in terms of which is farther left or right leftmost,rightmost,topmost,botmost = nil,nil,nil,nil if img1C.left < img2C.left then @@ -325,13 +325,13 @@ local function rCollidesWith(self, other) topmost = img2C botmost = img1C end - + --Then we determine the distance between the "extreme" edges- --distance between leftmost/right edge and rightmost/left edge --distance between topmost/bottom edge and bottommost/top edge local xdist = rightmost.left - leftmost.right local ydist = botmost.top - topmost.bottom - + --If both are negative, our rectangles intersect! return xdist <= 0 and ydist <= 0 end @@ -352,13 +352,13 @@ local function pCollidesWith(self, other) else img1 = self.image end if other.type == "animation" then img2 = other.frames[other.currentFrame] else img2 = other.image end - + --...then we position them... leftmost,rightmost,topmost,botmost = nil,nil,nil,nil --We also keep track of which is left and which is right- it doesn't matter in a rectangle --collision but it does in a pixel collision. img1T,img2T = {},{} - + if img1C.left < img2C.left then leftmost = img1C rightmost = img2C @@ -377,15 +377,15 @@ local function pCollidesWith(self, other) botmost = img1C img2T.top = true end - + --...and we again find the distances between the extreme edges. local xdist = rightmost.left - leftmost.right local ydist = botmost.top - topmost.bottom - + --If these distances are > 0 then we stop- no need to go any farther. if xdist > 0 or ydist > 0 then return false end - - + + for x = rightmost.left, rightmost.left + math.abs(xdist) do for y = botmost.top, botmost.top + math.abs(ydist) do --We know a collision has occurred if a pixel is occupied by both images. We do this by @@ -398,16 +398,16 @@ local function pCollidesWith(self, other) else testX = x - img1C.left + 1 end if img1T.top then testY = y - img1C.top + 1 else testY = y - img1C.top + 1 end - + local occupy1 = img1[testY + img1.bounds.y-1][testX + img1.bounds.x-1] ~= nil - + if img2T.left then testX = x - img2C.left + 1 else testX = x - img2C.left + 1 end if img2T.top then testY = y - img2C.top + 1 else testY = y - img2C.top + 1 end - + local occupy2 = img2[testY + img2.bounds.y-1][testX + img2.bounds.x-1] ~= nil - + if occupy1 and occupy2 then return true end end end @@ -429,7 +429,7 @@ local function moveTo(self, x, y) else image = self.image end - + self.x = x - image.bounds.x + 1 self.y = y - image.bounds.y + 1 end @@ -448,7 +448,7 @@ image:table = a table of the image. Indexed by height, a series of sub-tables, e dimensions:table = width = the width of the entire image in pixels height = the height of the entire image in pixels - + mirror:table = x:bool = whether or not the image is mirrored on the X axis y:bool = whether or not the image is mirrored on the Y axis @@ -464,19 +464,19 @@ draw:function = see drawS (above) y:number = the initial Y position of the sprite ]]-- function loadSprite(path, x, y) - local sprite = { + local sprite = { type = "sprite", x = x, y = y, image = { }, mirror = { x = false, y = false } } - + if fs.exists(path) then local file = io.open(path, "r" ) local leftX, rightX = math.huge, 0 local topY, botY = nil,nil - + local lcount = 0 for line in file:lines() do lcount = lcount+1 @@ -492,7 +492,7 @@ function loadSprite(path, x, y) end end file:close() - + sprite.image.bounds = { x = leftX, width = rightX - leftX + 1, @@ -503,10 +503,10 @@ function loadSprite(path, x, y) width = rightX, height = botY } - + sprite.x = sprite.x - leftX + 1 sprite.y = sprite.y - topY + 1 - + sprite.repaint = repaintS sprite.rCollidesWith = rCollidesWith sprite.pCollidesWith = pCollidesWith @@ -536,13 +536,13 @@ function loadAnimation(path, x, y, currentFrame) mirror = { x = false, y = false }, currentFrame = currentFrame } - + table.insert(anim.frames, { }) if fs.exists(path) then local file = io.open(path, "r") local leftX, rightX = math.huge, 0 local topY, botY = nil,nil - + local lcount = 0 for line in file:lines() do lcount = lcount+1 @@ -589,17 +589,17 @@ function loadAnimation(path, x, y, currentFrame) } anim.x = anim.x - leftX + 1 anim.y = anim.y - topY + 1 - - if not currentFrame or type(currentFrame) ~= "number" or currentFrame < 1 or - currentFrame > #anim.frames then - anim.currentFrame = 1 + + if not currentFrame or type(currentFrame) ~= "number" or currentFrame < 1 or + currentFrame > #anim.frames then + anim.currentFrame = 1 end - + anim.timerID = nil anim.lowerBound = 1 anim.upperBound = #anim.frames anim.updating = false - + anim.repaint = repaintA anim.rCollidesWith = rCollidesWith anim.pCollidesWith = pCollidesWith @@ -612,4 +612,4 @@ function loadAnimation(path, x, y, currentFrame) else error(path.." not found!") end -end \ No newline at end of file +end diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua index 0c214a60d..826468eb7 100644 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua +++ b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua @@ -68,7 +68,7 @@ local px,py,pz,pfx,pfz = 0,0,0,0,0 --The form of layering used local layering = "up" ---The animation state of the selection rectangle and image buffer +--The animation state of the selection rectangle and image buffer local rectblink = 0 --The ID for the timer local recttimer = nil @@ -268,7 +268,7 @@ local helpTopics = { message = "Clicking on the mode display at the bottom of the screen will open the options menu. Here you can".. " activate all of the modes in the program with a simple mouse click. Pressing left control will open up the".. " file menu automatically.", - controls = { + controls = { { "leftCtrl", "Opens the file menu" }, { "leftAlt", "Opens the paint menu" } } @@ -317,8 +317,8 @@ local toplim,botlim,leflim,riglim = nil,nil,nil,nil --The selected path local sPath = nil ---[[ - Section: Helpers +--[[ + Section: Helpers ]]-- --[[Converts a colour parameter into a single-digit hex coordinate for the colour @@ -326,12 +326,12 @@ local sPath = nil Returns:string A string conversion of the colour ]]-- local function getHexOf(colour) - if not colour or not tonumber(colour) then - return " " + if not colour or not tonumber(colour) then + return " " end local value = math.log(colour)/math.log(2) - if value > 9 then - value = hexnums[value] + if value > 9 then + value = hexnums[value] end return value end @@ -355,7 +355,7 @@ end local function updateImageLims(forAllFrames) local f,l = sFrame,sFrame if forAllFrames == true then f,l = 1,framecount end - + toplim,botlim,leflim,riglim = nil,nil,nil,nil for locf = f,l do for y,_ in pairs(frames[locf]) do @@ -371,7 +371,7 @@ local function updateImageLims(forAllFrames) end end end - + --There is just... no easier way to do this. It's horrible, but necessary if textEnabled then for locf = f,l do @@ -406,19 +406,19 @@ end function calculateMaterials() updateImageLims(animated) requiredMaterials = {} - for i=1,16 do - requiredMaterials[i] = 0 + for i=1,16 do + requiredMaterials[i] = 0 end - + if not toplim then return end - + for i=1,#frames do for y = toplim, botlim do for x = leflim, riglim do if type(frames[i][y][x]) == "number" then requiredMaterials[math.log(frames[i][y][x],10)/math.log(2,10) + 1] = requiredMaterials[math.log(frames[i][y][x],10)/math.log(2,10) + 1] + 1 - end + end end end end @@ -455,16 +455,16 @@ end local function rsTimeReceive(timeout) local timerID if timeout then timerID = os.startTimer(timeout) end - + local id,key,msg = nil,nil while true do id,key,msg = os.pullEvent() - + if id == "timer" then if key == timerID then return else updateTimer(key) end end - if id == "rednet_message" then + if id == "rednet_message" then return key,msg end end @@ -490,9 +490,9 @@ local function drawPictureTable(image, xinit, yinit, alpha) end end ---[[ - Section: Loading -]]-- +--[[ + Section: Loading +]]-- --[[Loads a non-animted paint file into the program Params: path:string = The path in which the file is located @@ -526,7 +526,7 @@ local function loadNFT(path) frames[sFrame] = { } frames[sFrame].text = { } frames[sFrame].textcol = { } - + if fs.exists(path) then local file = io.open(path, "r") local sLine = file:read() @@ -535,7 +535,7 @@ local function loadNFT(path) table.insert(frames[sFrame], num, {}) table.insert(frames[sFrame].text, num, {}) table.insert(frames[sFrame].textcol, num, {}) - + --As we're no longer 1-1, we keep track of what index to write to local writeIndex = 1 --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour @@ -614,13 +614,13 @@ local function saveNFP(path) local file = io.open(path, "w") updateImageLims(false) - if not toplim then + if not toplim then file:close() return end for y=1,botlim do local line = "" - if frames[sFrame][y] then + if frames[sFrame][y] then for x=1,riglim do line = line..getHexOf(frames[sFrame][y][x]) end @@ -639,7 +639,7 @@ local function saveNFT(path) if not fs.exists(sDir) then fs.makeDir(sDir) end - + local file = io.open(path, "w") updateImageLims(false) if not toplim then @@ -678,17 +678,17 @@ local function saveNFA(path) if not fs.exists(sDir) then fs.makeDir(sDir) end - + local file = io.open(path, "w") updateImageLims(true) - if not toplim then + if not toplim then file:close() return end for i=1,#frames do for y=1,botlim do local line = "" - if frames[i][y] then + if frames[i][y] then for x=1,riglim do line = line..getHexOf(frames[i][y][x]) end @@ -709,14 +709,14 @@ local function init() if textEnabled then loadNFT(sPath) table.insert(ddModes, 2, { "text", "textpaint", name = "text"}) - elseif animated then + elseif animated then loadNFA(sPath) table.insert(ddModes, #ddModes, { "record", "play", name = "anim" }) table.insert(ddModes, #ddModes, { "go to", "remove", name = "frames"}) table.insert(ddModes[2], #ddModes[2], "blueprint on") table.insert(ddModes[2], #ddModes[2], "layers on") - else - loadNFP(sPath) + else + loadNFP(sPath) table.insert(ddModes[2], #ddModes[2], "blueprint on") end @@ -725,8 +725,8 @@ local function init() end end ---[[ - Section: Drawing +--[[ + Section: Drawing ]]-- @@ -747,7 +747,7 @@ local function drawLogo() msg = "By NitrogenFingers" term.setCursorPos(w/2 - #msg/2, h-2) term.write(msg) - + os.pullEvent() end @@ -772,13 +772,13 @@ local function drawCanvas() if pz >= 1 and pz <= #frames then sFrame = pz end - + if py < sy then sy = py elseif py > sy + h - 1 then sy = py + h - 1 end if px < sx then sx = px elseif px > sx + w - 2 then sx = px + w - 2 end end - + if pfx == 1 then turtlechar = ">" elseif pfx == -1 then turtlechar = "<" elseif pfz == 1 then turtlechar = "V" @@ -794,10 +794,10 @@ local function drawCanvas() else topLayer,botLayer = sFrame,sFrame end - + for currframe = botLayer,topLayer,1 do for y=sy+1,sy+h-1 do - if frames[currframe][y] then + if frames[currframe][y] then for x=sx+1,sx+w-2 do term.setCursorPos(x-sx,y-sy) if frames[currframe][y][x] then @@ -808,7 +808,7 @@ local function drawCanvas() else term.write(" ") end - else + else tileExists = false for i=currframe-1,botLayer,-1 do if frames[i][y][x] then @@ -816,7 +816,7 @@ local function drawCanvas() break end end - + if not tileExists then if blueprint then term.setBackgroundColour(colours.blue) @@ -835,7 +835,7 @@ local function drawCanvas() term.write(" ") end else - term.setBackgroundColour(alphaC) + term.setBackgroundColour(alphaC) if textEnabled and frames[currframe].textcol[y][x] and frames[currframe].text[y][x] then term.setTextColour(frames[currframe].textcol[y][x]) term.write(frames[currframe].text[y][x]) @@ -849,7 +849,7 @@ local function drawCanvas() else for x=sx+1,sx+w-2 do term.setCursorPos(x-sx,y-sy) - + tileExists = false for i=currframe-1,botLayer,-1 do if frames[i][y] and frames[i][y][x] then @@ -857,7 +857,7 @@ local function drawCanvas() break end end - + if not tileExists then if blueprint then term.setBackgroundColour(colours.blue) @@ -876,7 +876,7 @@ local function drawCanvas() term.write(" ") end else - term.setBackgroundColour(alphaC) + term.setBackgroundColour(alphaC) term.write(" ") end end @@ -884,7 +884,7 @@ local function drawCanvas() end end end - + --Then the printer, if he's on if state == "active print" then local bgColour = alphaC @@ -899,14 +899,14 @@ local function drawCanvas() bgColour = frames[sFrame][py-sy][px-sx] elseif blueprint then bgColour = colours.blue end end - + term.setBackgroundColour(bgColour) if bgColour == colours.black then term.setTextColour(colours.white) else term.setTextColour(colours.black) end - + term.write(turtlechar) end - + --Then the buffer if selectrect then if buffer and rectblink == 1 then @@ -920,12 +920,12 @@ local function drawCanvas() end end end - + --This draws the "selection" box local add = nil if buffer then term.setBackgroundColour(colours.lightGrey) - else + else term.setBackgroundColour(colours.grey) end for i=selectrect.x1, selectrect.x2 do @@ -947,7 +947,7 @@ local function drawCanvas() end end ---[[Draws the colour picker on the right side of the screen, the colour pallette and the footer with any +--[[Draws the colour picker on the right side of the screen, the colour pallette and the footer with any messages currently being displayed Params: none Returns:nil @@ -1001,7 +1001,7 @@ local function drawInterface() end --Footer if inMenu then return end - + term.setCursorPos(1, h) term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.grey) @@ -1016,14 +1016,14 @@ local function drawInterface() term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.grey) term.write(getStateMessage()) - + local coords="X:"..sx.." Y:"..sy if animated then coords = coords.." Frame:"..sFrame.."/"..framecount.." " end term.setCursorPos(w-#coords+1,h) if state == "play" then term.setBackgroundColour(colours.lime) elseif record then term.setBackgroundColour(colours.red) end term.write(coords) - + if animated then term.setCursorPos(w-1,h) term.setBackgroundColour(colours.grey) @@ -1075,17 +1075,17 @@ local function drawHelpScreen() print(helpTopics[selectedHelp].controls[i][2]) end end - + local id,p1,p2,p3 = os.pullEvent() - + if id == "timer" then updateTimer(p1) - elseif id == "key" then + elseif id == "key" then if selectedHelp then selectedHelp = nil else break end elseif id == "mouse_click" then - if not selectedHelp then + if not selectedHelp then if p3 >=3 and p3 <= 2+#helpTopics then - selectedHelp = p3-2 + selectedHelp = p3-2 else break end else selectedHelp = nil @@ -1137,7 +1137,7 @@ local function wprintOffCenter(msg, height, width, offset) end term.setCursorPos(width/2 - #string.sub(msg, ops)/2 + offset, height + inc) term.write(string.sub(msg, ops)) - + return inc + 1 end @@ -1151,7 +1151,7 @@ local function displayConfirmDialogue(ctitle, msg) local dialogoffset = 8 --We actually print twice- once to get the lines, second time to print proper. Easier this way. local lines = wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2) - + term.setCursorPos(dialogoffset, 3) term.setBackgroundColour(colours.grey) term.setTextColour(colours.lightGrey) @@ -1163,11 +1163,11 @@ local function displayConfirmDialogue(ctitle, msg) term.setCursorPos(dialogoffset, 4) term.write(string.rep(" ", w - dialogoffset * 2)) for i=5,5+lines do - term.setCursorPos(dialogoffset, i) + term.setCursorPos(dialogoffset, i) term.write(" "..string.rep(" ", w - (dialogoffset) * 2 - 2).." ") end wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2) - + --In the event of a message, the player hits anything to continue while true do local id,key = os.pullEvent() @@ -1190,24 +1190,24 @@ local function displayDropDown(x, y, options) for i=1,#options do local currVal = options[i] if type(currVal) == "table" then currVal = currVal.name end - + longestX = math.max(longestX, #currVal) end local xOffset = math.max(0, longestX - ((w-2) - x) + 1) local yOffset = math.max(0, #options - ((h-1) - y)) - + local clickTimes = 0 local tid = nil local selection = nil while clickTimes < 2 do drawCanvas() drawInterface() - + term.setCursorPos(x-xOffset,y-yOffset) term.setBackgroundColour(colours.grey) term.setTextColour(colours.lightGrey) term.write(options.name..string.rep(" ", longestX-#options.name + 2)) - + for i=1,#options do term.setCursorPos(x-xOffset, y-yOffset+i) if i==selection and clickTimes % 2 == 0 then @@ -1218,7 +1218,7 @@ local function displayDropDown(x, y, options) term.setTextColour(colours.grey) end local currVal = options[i] - if type(currVal) == "table" then + if type(currVal) == "table" then term.write(currVal.name..string.rep(" ", longestX-#currVal.name + 1)) term.setBackgroundColour(colours.grey) term.setTextColour(colours.lightGrey) @@ -1227,18 +1227,18 @@ local function displayDropDown(x, y, options) term.write(currVal..string.rep(" ", longestX-#currVal + 2)) end end - + local id, p1, p2, p3 = os.pullEvent() if id == "timer" then - if p1 == tid then + if p1 == tid then clickTimes = clickTimes + 1 - if clickTimes > 2 then + if clickTimes > 2 then break - else - tid = os.startTimer(0.1) + else + tid = os.startTimer(0.1) end - else - updateTimer(p1) + else + updateTimer(p1) drawCanvas() drawInterface() end @@ -1252,15 +1252,15 @@ local function displayDropDown(x, y, options) end end end - + if type(selection) == "number" then selection = options[selection] end - - if type(selection) == "string" then + + if type(selection) == "string" then inDropDown = false return selection - elseif type(selection) == "table" then + elseif type(selection) == "table" then return displayDropDown(x, y, selection) end end @@ -1285,16 +1285,16 @@ local function readInput(lim) --As events queue immediately, we may get an unwanted key... this will solve that problem local inputTimer = os.startTimer(0.01) local keysAllowed = false - + while true do local id,key = os.pullEvent() - + if keysAllowed then if id == "key" and key == 14 and #inputString > 0 then inputString = string.sub(inputString, 1, #inputString-1) term.setCursorPos(ox + #inputString,oy) term.write(" ") - elseif id == "key" and key == 28 and inputString ~= string.rep(" ", #inputString) then + elseif id == "key" and key == 28 and inputString ~= string.rep(" ", #inputString) then break elseif id == "key" and key == keys.leftCtrl then return "" @@ -1302,9 +1302,9 @@ local function readInput(lim) inputString = inputString..key end end - + if id == "timer" then - if key == inputTimer then + if key == inputTimer then keysAllowed = true else updateTimer(key) @@ -1318,7 +1318,7 @@ local function readInput(lim) term.write(inputString) term.setCursorPos(ox + #inputString, oy) end - + while string.sub(inputString, 1, 1) == " " do inputString = string.sub(inputString, 2, #inputString) end @@ -1326,12 +1326,12 @@ local function readInput(lim) inputString = string.sub(inputString, 1, #inputString-1) end term.setCursorBlink(false) - + return inputString end ---[[ - Section: Image tools +--[[ + Section: Image tools ]]-- @@ -1341,13 +1341,13 @@ end ]]-- local function copyToBuffer(removeImage) buffer = { width = selectrect.x2 - selectrect.x1 + 1, height = selectrect.y2 - selectrect.y1 + 1, contents = { } } - + local containsSomething = false for y=1,buffer.height do buffer.contents[y] = { } local f,l = sFrame,sFrame if record then f,l = 1, framecount end - + for fra = f,l do if frames[fra][selectrect.y1 + y - 1] then for x=1,buffer.width do @@ -1372,7 +1372,7 @@ local function copyFromBuffer(removeBuffer) for y = 1, math.min(buffer.height,selectrect.y2-selectrect.y1+1) do local f,l = sFrame, sFrame if record then f,l = 1, framecount end - + for fra = f,l do if not frames[fra][selectrect.y1+y-1] then frames[fra][selectrect.y1+y-1] = { } end for x = 1, math.min(buffer.width,selectrect.x2-selectrect.x1+1) do @@ -1380,7 +1380,7 @@ local function copyFromBuffer(removeBuffer) end end end - + if removeBuffer then buffer = nil end end @@ -1394,7 +1394,7 @@ local function moveImage(newx,newy) if newx <=0 or newy <=0 then return end local f,l = sFrame,sFrame if record then f,l = 1,framecount end - + for i=f,l do local newlines = { } for y=toplim,botlim do @@ -1418,7 +1418,7 @@ local function moveImage(newx,newy) end end end - + newlines.textcol = { } for y=toplim,botlim do local line = frames[i].textcol[y] @@ -1430,7 +1430,7 @@ local function moveImage(newx,newy) end end end - + frames[i] = newlines end end @@ -1451,7 +1451,7 @@ local function clearImage() if string.find(string.upper(readInput(1)), "Y") then local f,l = sFrame,sFrame if record then f,l = 1,framecount end - + for i=f,l do frames[i] = { } end @@ -1470,9 +1470,9 @@ end local function floodFill(x, y, targetColour, newColour) if not newColour or not targetColour then return end local nodeList = { } - + table.insert(nodeList, {x = x, y = y}) - + while #nodeList > 0 do local node = nodeList[1] if frames[sFrame][node.y] and frames[sFrame][node.y][node.x] == targetColour then @@ -1486,8 +1486,8 @@ local function floodFill(x, y, targetColour, newColour) end end ---[[ - Section: Animation Tools +--[[ + Section: Animation Tools ]]-- --[[Enters play mode, allowing the animation to play through. Interface is restricted to allow this, @@ -1498,14 +1498,14 @@ end local function playAnimation() state = "play" selectedrect = nil - + local animt = os.startTimer(animtime) repeat drawCanvas() drawInterface() - + local id,key,_,y = os.pullEvent() - + if id=="timer" then if key == animt then animt = os.startTimer(animtime) @@ -1536,15 +1536,15 @@ local function changeFrame(newframe) term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.grey) term.clearLine() - + term.write("Go to frame: ") newframe = tonumber(readInput(2)) if not newframe or newframe <= 0 then inMenu = false - return + return end elseif newframe <= 0 then return end - + if newframe > framecount then for i=framecount+1,newframe do frames[i] = {} @@ -1570,12 +1570,12 @@ local function removeFramesAfter(frame) if frame==framecount then return end drawMessage("Remove frames "..(frame+1).."/"..framecount.."? Y/N :") local answer = string.upper(readInput(1)) - - if string.find(answer, string.upper("Y")) ~= 1 then + + if string.find(answer, string.upper("Y")) ~= 1 then inMenu = false - return + return end - + for i=frame+1, framecount do frames[i] = nil end @@ -1596,7 +1596,7 @@ end local function getLeft(curx, curz) local hand = "left" if layering == "up" then hand = "right" end - + if hand == "right" then if curx == 1 then return 0,-1 end if curx == -1 then return 0,1 end @@ -1619,7 +1619,7 @@ end local function getRight(curx, curz) local hand = "left" if layering == "up" then hand = "right" end - + if hand == "right" then if curx == 1 then return 0,1 end if curx == -1 then return 0,-1 end @@ -1647,7 +1647,7 @@ local function locatePrinters() drawCanvas() drawInterface() state = oldState - + local modemOpened = false for k,v in pairs(rs.getSides()) do if peripheral.isPresent(v) and peripheral.getType(v) == "modem" then @@ -1656,17 +1656,17 @@ local function locatePrinters() break end end - + if not modemOpened then displayConfirmDialogue("Modem not found!", "No modem peripheral. Must have network modem to locate printers.") return false end - + rednet.broadcast("$3DPRINT IDENTIFY") - + while true do local id, msg = rsTimeReceive(1) - + if not id then break end if string.find(msg, "$3DPRINT IDACK") == 1 then msg = string.gsub(msg, "$3DPRINT IDACK ", "") @@ -1674,7 +1674,7 @@ local function locatePrinters() table.insert(printerNames, msg) end end - + if #printerList == 0 then displayConfirmDialogue("Printers not found!", "No active printers found in proximity of this computer.") return false @@ -1692,7 +1692,7 @@ local function sendPC(command,param) local msg = "$PC "..command if param then msg = msg.." "..param end rednet.send(printerList[selectedPrinter], msg) - + while true do local id,key = rsTimeReceive() if id == printerList[selectedPrinter] then @@ -1713,7 +1713,7 @@ local function sendPC(command,param) end end end - + --Changes to position are handled after the event has been successfully completed if command == "FW" then px = px + pfx @@ -1724,13 +1724,13 @@ local function sendPC(command,param) elseif command == "UP" then if layering == "up" then py = py + 1 - else + else py = py - 1 end elseif command == "DW" then if layering == "up" then py = py - 1 - else + else py = py + 1 end elseif command == "TL" then @@ -1741,7 +1741,7 @@ local function sendPC(command,param) pfx = -pfx pfz = -pfz end - + drawCanvas() drawInterface() end @@ -1788,7 +1788,7 @@ local function performPrint() --An up layering starts our builder bot on the bottom left corner of our build px,py,pz = leflim, 0, botlim + 1 pfx,pfz = 0,-1 - + --We move him forward and up a bit from his original position. sendPC("FW") sendPC("UP") @@ -1801,7 +1801,7 @@ local function performPrint() else rowbot,rowtop,rowinc = toplim,botlim,1 end - + for rows = rowbot,rowtop,rowinc do --Then we decide if we're going left or right, depending on what side we're on local linebot,linetop,lineinc = nil,nil,nil @@ -1814,7 +1814,7 @@ local function performPrint() turnToFace(-1,0) linebot,linetop,lineinc = riglim,leflim,-1 end - + for lines = linebot,linetop,lineinc do --We move our turtle forward, placing the right material at each step local material = frames[py][pz][px] @@ -1827,7 +1827,7 @@ local function performPrint() sendPC("FW") end end - + --The printer then has to do a U-turn, depending on which way he's facing and --which way he needs to go local temppfx,temppfz = getLeft(pfx,pfz) @@ -1873,7 +1873,7 @@ local function performPrint() while pz < #frames do sendPC("FW") end - + --For each layer in the frame we build our wall, the move back for layers = 1,#frames do --We first decide if we're going left or right based on our position @@ -1883,7 +1883,7 @@ local function performPrint() else rowbot,rowtop,rowinc = riglim,leflim,-1 end - + for rows = rowbot,rowtop,rowinc do --Then we decide if we're going up or down, depending on our given altitude local linebot,linetop,lineinc = nil,nil,nil @@ -1892,7 +1892,7 @@ local function performPrint() else linebot,linetop,lineinc = toplim,botlim,1 end - + for lines = linebot,linetop,lineinc do --We move our turtle up/down, placing the right material at each step local material = frames[pz][py][px] @@ -1906,14 +1906,14 @@ local function performPrint() else sendPC("UP") end end end - + if rows ~= rowtop then turnToFace(rowinc,0) sendPC("FW") turnToFace(0,1) end end - + if layers ~= #frames then sendPC("TU") sendPC("FW") @@ -1927,14 +1927,14 @@ local function performPrint() end turnToFace(0,1) end - + sendPC("DE") - + displayConfirmDialogue("Print complete", "The 3D print was successful.") end ---[[ - Section: Interface +--[[ + Section: Interface ]]-- --[[Runs the printing interface. Allows users to find/select a printer, the style of printing to perform and to begin the operation @@ -1953,7 +1953,7 @@ local function runPrintInterface() if not locatePrinters() then return false end - + layering = "up" requirementsDisplayed = false selectedPrinter = 1 @@ -1967,7 +1967,7 @@ local function runPrintInterface() drawInterface() term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.black) - + local msg = "3D Printing" term.setCursorPos(w/2-#msg/2 - 2, 1) term.write(msg) @@ -1982,7 +1982,7 @@ local function runPrintInterface() term.write(msg) term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.black) - + term.setCursorPos(7, 2) term.write("Layering") drawPictureTable(layerUpIcon, 3, 3, colours.white) @@ -2001,7 +2001,7 @@ local function runPrintInterface() end term.setCursorPos(12, 9) term.write("Forward") - + term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.black) term.setCursorPos(31, 2) @@ -2014,16 +2014,16 @@ local function runPrintInterface() term.setTextColour(colours.red) end term.write(" "..printerNames[selectedPrinter].." ") - + term.setBackgroundColour(colours.grey) term.setTextColour(colours.lightGrey) term.setCursorPos(25, 10) term.write(" Cancel ") term.setCursorPos(40, 10) term.write(" Print ") - + local id, p1, p2, p3 = os.pullEvent() - + if id == "timer" then updateTimer(p1) elseif id == "mouse_click" then @@ -2052,7 +2052,7 @@ local function runPrintInterface() ready = false while true do local id,msg = rsTimeReceive(10) - + if id == printerList[selectedPrinter] and msg == "$3DPRINT ACTACK" then ready = true break @@ -2077,100 +2077,100 @@ end ]]-- local function performSelection(mode) if not mode or mode == "" then return - + elseif mode == "help" then drawHelpScreen() - + elseif mode == "blueprint on" then blueprint = true ddModes[2][3] = "blueprint off" - + elseif mode == "blueprint off" then blueprint = false ddModes[2][3] = "blueprint on" - + elseif mode == "layers on" then layerDisplay = true ddModes[2][4] = "layers off" - + elseif mode == "layers off" then layerDisplay = false ddModes[2][4] = "layers on" - + elseif mode == "direction on" then printDirection = true ddModes[2][5] = "direction off" - + elseif mode == "direction off" then printDirection = false ddModes[2][5] = "direction on" - + elseif mode == "go to" then changeFrame() - + elseif mode == "remove" then removeFramesAfter(sFrame) - + elseif mode == "play" then playAnimation() - + elseif mode == "copy" then if selectrect and selectrect.x1 ~= selectrect.x2 then copyToBuffer(false) end - + elseif mode == "cut" then - if selectrect and selectrect.x1 ~= selectrect.x2 then + if selectrect and selectrect.x1 ~= selectrect.x2 then copyToBuffer(true) end - + elseif mode == "paste" then - if selectrect and selectrect.x1 ~= selectrect.x2 then + if selectrect and selectrect.x1 ~= selectrect.x2 then copyFromBuffer(false) end - + elseif mode == "hide" then selectrect = nil if state == "select" then state = "corner select" end - + elseif mode == "alpha to left" then if lSel then alphaC = lSel end - + elseif mode == "alpha to right" then if rSel then alphaC = rSel end - + elseif mode == "record" then record = not record - + elseif mode == "clear" then if state=="select" then buffer = nil else clearImage() end - + elseif mode == "select" then if state=="corner select" or state=="select" then state = "paint" elseif selectrect and selectrect.x1 ~= selectrect.x2 then state = "select" else - state = "corner select" + state = "corner select" end - + elseif mode == "print" then state = "print" runPrintInterface() state = "paint" - + elseif mode == "save" then if animated then saveNFA(sPath) elseif textEnabled then saveNFT(sPath) else saveNFP(sPath) end - + elseif mode == "exit" then isRunning = false - + elseif mode ~= state then state = mode else state = "paint" - + end end @@ -2184,12 +2184,12 @@ local function handleEvents() while isRunning do drawCanvas() drawInterface() - + if state == "text" then term.setCursorPos(textCurX - sx, textCurY - sy) term.setCursorBlink(true) end - + local id,p1,p2,p3 = os.pullEvent() term.setCursorBlink(false) if id=="timer" then @@ -2212,20 +2212,20 @@ local function handleEvents() if state=="pippette" then if p1==1 then if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then - lSel = frames[sFrame][p3+sy][p2+sx] + lSel = frames[sFrame][p3+sy][p2+sx] end elseif p1==2 then if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then - rSel = frames[sFrame][p3+sy][p2+sx] + rSel = frames[sFrame][p3+sy][p2+sx] end end elseif state=="move" then updateImageLims(record) moveImage(p2,p3) elseif state=="flood" then - if p1 == 1 and lSel and frames[sFrame][p3+sy] then + if p1 == 1 and lSel and frames[sFrame][p3+sy] then floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],lSel) - elseif p1 == 2 and rSel and frames[sFrame][p3+sy] then + elseif p1 == 2 and rSel and frames[sFrame][p3+sy] then floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],rSel) end elseif state=="corner select" then @@ -2234,10 +2234,10 @@ local function handleEvents() elseif selectrect.x1 ~= p2+sx and selectrect.y1 ~= p3+sy then if p2+sx w + sx - 2 then sx = textCurX - w + 2 end elseif tonumber(p1) then @@ -2335,16 +2335,16 @@ local function handleEvents() textCurY = textCurY+1 if textCurY > h + sy - 1 then sy = textCurY - h + 1 end end - + elseif p1==keys.leftCtrl then - local sel = displayDropDown(1, h-1, ddModes[#ddModes]) + local sel = displayDropDown(1, h-1, ddModes[#ddModes]) performSelection(sel) elseif p1==keys.leftAlt then - local sel = displayDropDown(1, h-1, ddModes[1]) + local sel = displayDropDown(1, h-1, ddModes[1]) performSelection(sel) - elseif p1==keys.h then + elseif p1==keys.h then performSelection("help") - elseif p1==keys.x then + elseif p1==keys.x then performSelection("cut") elseif p1==keys.c then performSelection("copy") @@ -2415,7 +2415,7 @@ local function handleEvents() selectrect.y1 = selectrect.y1-1 selectrect.y2 = selectrect.y2-1 elseif sy > 0 then sy=sy-1 end - elseif p1==keys.down then + elseif p1==keys.down then if state == "move" then updateImageLims(record) if toplim and leflim then @@ -2431,7 +2431,7 @@ local function handleEvents() end --[[ - Section: Main + Section: Main ]]-- if not term.isColour() then @@ -2475,15 +2475,15 @@ if fs.exists(sPath) then print("Can only edit .nfp, .nft and .nfa files:",string.find(sPath, ".nfp"),#sPath-3) return end - + if string.find(sPath, ".nfa") == #sPath-3 then animated = true end - + if string.find(sPath, ".nft") == #sPath-3 then textEnabled = true - end - + end + if string.find(sPath, ".nfp") == #sPath-3 and animated then print("Convert to nfa? Y/N") if string.find(string.lower(io.read()), "y") then @@ -2494,24 +2494,24 @@ if fs.exists(sPath) then animated = false end end - + --Again this is possible, I just haven't done it. Maybe I will? if textEnabled and (string.find(sPath, ".nfp") == #sPath-3 or string.find(sPath, ".nfa") == #sPath-3) then print("Cannot convert to nft") end else - if not animated and not textEnabled and string.find(sPath, ".nfp") ~= #sPath-3 then + if not animated and not textEnabled and string.find(sPath, ".nfp") ~= #sPath-3 then sPath = sPath..".nfp" - elseif animated and string.find(sPath, ".nfa") ~= #sPath-3 then + elseif animated and string.find(sPath, ".nfa") ~= #sPath-3 then sPath = sPath..".nfa" elseif textEnabled and string.find(sPath, ".nft") ~= #sPath-3 then sPath = sPath..".nft" end -end +end drawLogo() init() handleEvents() term.setBackgroundColour(colours.black) -shell.run("clear") \ No newline at end of file +shell.run("clear") diff --git a/src/main/resources/data/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua b/src/main/resources/data/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua index bcd57c718..2a1a447a4 100644 --- a/src/main/resources/data/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua +++ b/src/main/resources/data/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua @@ -175,4 +175,4 @@ drawScreen() while true do loop() parallel.waitForAny(loop, compute) -end \ No newline at end of file +end 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 09115ec12..000000000 --- a/src/main/resources/data/computercraft/recipes/cable.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - " # ", - "#R#", - " # " - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" } - }, - "result": { "item": "computercraft:cable", "count": 6 } -} 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 81afaad43..000000000 --- a/src/main/resources/data/computercraft/recipes/computer_advanced.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#G#" - ], - "key": { - "#": { "tag": "forge:ingots/gold" }, - "R": { "tag": "forge:dusts/redstone" }, - "G": { "item": "minecraft:glass_pane" } - }, - "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 c89aa7f6d..000000000 --- a/src/main/resources/data/computercraft/recipes/computer_command.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#G#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "item": "minecraft:command_block" }, - "G": { "item": "minecraft:glass_pane" } - }, - "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 1761701bc..000000000 --- a/src/main/resources/data/computercraft/recipes/computer_normal.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#G#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" }, - "G": { "item": "minecraft:glass_pane" } - }, - "result": { "item": "computercraft:computer_normal" } -} 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 59c78b50f..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_drive.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#R#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" } - }, - "result": { "item": "computercraft:disk_drive" } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json deleted file mode 100644 index a27ee37c6..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:black_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 1118481 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_10.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_10.json deleted file mode 100644 index 26b83fe6b..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_10.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:pink_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 15905484 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_11.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_11.json deleted file mode 100644 index 40d6157c0..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_11.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:lime_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 8375321 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json deleted file mode 100644 index 505066e7a..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:yellow_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 14605932 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_13.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_13.json deleted file mode 100644 index e270135ef..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_13.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:light_blue_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 10072818 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_14.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_14.json deleted file mode 100644 index 73794dac1..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_14.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:magenta_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 15040472 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_15.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_15.json deleted file mode 100644 index 13ff4dd71..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_15.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:orange_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 15905331 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json deleted file mode 100644 index 2fa82adad..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:white_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 15790320 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json deleted file mode 100644 index 21ab48568..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:red_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 13388876 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json deleted file mode 100644 index a164af6cb..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:green_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 5744206 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json deleted file mode 100644 index 7109021e3..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:brown_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 8349260 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json deleted file mode 100644 index 538f14349..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:blue_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 3368652 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_6.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_6.json deleted file mode 100644 index 6a9c1ed5b..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_6.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:purple_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 11691749 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_7.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_7.json deleted file mode 100644 index 6f6a442f7..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_7.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:cyan_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 5020082 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_8.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_8.json deleted file mode 100644 index bd8bc8f42..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_8.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:light_gray_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 10066329 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_9.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_9.json deleted file mode 100644 index 67ad7f58e..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_9.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:gray_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 5000268 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_speaker.json b/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_speaker.json deleted file mode 100644 index e60e9ea93..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_speaker.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_advanced", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:speaker" }, - "T": { "item": "computercraft:pocket_computer_advanced" } - }, - "result": { "item": "computercraft:pocket_computer_advanced", "nbt": { "Upgrade": "computercraft:speaker" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 878afe1a5..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_advanced", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_advanced" }, - "T": { "item": "computercraft:pocket_computer_advanced" } - }, - "result": { "item": "computercraft:pocket_computer_advanced", "nbt": { "Upgrade": "computercraft:wireless_modem_advanced" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json deleted file mode 100644 index 1bd86cca0..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_advanced", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_normal" }, - "T": { "item": "computercraft:pocket_computer_advanced" } - }, - "result": { "item": "computercraft:pocket_computer_advanced", "nbt": { "Upgrade": "computercraft:wireless_modem_normal" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_speaker.json b/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_speaker.json deleted file mode 100644 index ba569ec7a..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_speaker.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_normal", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:speaker" }, - "T": { "item": "computercraft:pocket_computer_normal" } - }, - "result": { "item": "computercraft:pocket_computer_normal", "nbt": { "Upgrade": "computercraft:speaker" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 3c008706d..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_normal", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_advanced" }, - "T": { "item": "computercraft:pocket_computer_normal" } - }, - "result": { "item": "computercraft:pocket_computer_normal", "nbt": { "Upgrade": "computercraft:wireless_modem_advanced" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json deleted file mode 100644 index 85e7a1d5f..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_normal", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_normal" }, - "T": { "item": "computercraft:pocket_computer_normal" } - }, - "result": { "item": "computercraft:pocket_computer_normal", "nbt": { "Upgrade": "computercraft:wireless_modem_normal" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_speaker.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_speaker.json deleted file mode 100644 index fe43a6734..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_speaker.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:speaker" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "computercraft:speaker" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json deleted file mode 100644 index a6af8052c..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_advanced" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "computercraft:wireless_modem_advanced" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json deleted file mode 100644 index 564e31980..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_normal" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "computercraft:wireless_modem_normal" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_crafting_table.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_crafting_table.json deleted file mode 100644 index 3e44088ca..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_crafting_table.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:crafting_table" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:crafting_table" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_axe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_axe.json deleted file mode 100644 index 9727781b2..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_axe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_axe" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_axe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json deleted file mode 100644 index a36a0b9f5..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_hoe" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_hoe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json deleted file mode 100644 index 27da4aabd..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_pickaxe" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_pickaxe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json deleted file mode 100644 index 72bc79f11..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_shovel" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_shovel" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_sword.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_sword.json deleted file mode 100644 index 3035c91e0..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_sword.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_sword" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_sword" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_speaker.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_speaker.json deleted file mode 100644 index 20788c88d..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_speaker.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:speaker" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "computercraft:speaker" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json deleted file mode 100644 index b7b7e6ef1..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_advanced" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "computercraft:wireless_modem_advanced" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json deleted file mode 100644 index 5722d7029..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_normal" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "computercraft:wireless_modem_normal" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_crafting_table.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_crafting_table.json deleted file mode 100644 index 14c8f23e3..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_crafting_table.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:crafting_table" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:crafting_table" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_axe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_axe.json deleted file mode 100644 index e0c2104d2..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_axe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_axe" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_axe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_hoe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_hoe.json deleted file mode 100644 index 981e41774..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_hoe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_hoe" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_hoe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json deleted file mode 100644 index 459ca8233..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_pickaxe" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_pickaxe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_shovel.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_shovel.json deleted file mode 100644 index fc414008b..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_shovel.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_shovel" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_shovel" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_sword.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_sword.json deleted file mode 100644 index 0c2321121..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_sword.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_sword" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_sword" } } -} 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 6dc27ecff..000000000 --- a/src/main/resources/data/computercraft/recipes/monitor_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#G#", - "###" - ], - "key": { - "#": { "tag": "forge:ingots/gold" }, - "G": { "item": "minecraft:glass_pane" } - }, - "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 8ee786686..000000000 --- a/src/main/resources/data/computercraft/recipes/monitor_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#G#", - "###" - ], - "key": { - "#": { "tag": "forge:stone" }, - "G": { "item": "minecraft:glass_pane" } - }, - "result": { "item": "computercraft:monitor_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 f4119b18b..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_computer_advanced.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#A#", - "#G#" - ], - "key": { - "#": { "tag": "forge:ingots/gold" }, - "G": { "item": "minecraft:glass_pane" }, - "A": { "item": "minecraft:golden_apple" } - }, - "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 f01612779..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_computer_normal.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#A#", - "#G#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "G": { "item": "minecraft:glass_pane" }, - "A": { "item": "minecraft:golden_apple" } - }, - "result": { "item": "computercraft:pocket_computer_normal" } -} 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 4d120a541..000000000 --- a/src/main/resources/data/computercraft/recipes/printer.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#D#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "item": "minecraft:glass_pane" }, - "D": { "tag": "forge:dyes" } - }, - "result": { "item": "computercraft:printer" } -} 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 6c0cf7595..000000000 --- a/src/main/resources/data/computercraft/recipes/speaker.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#N#", - "#R#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" }, - "N": { "item": "minecraft:note_block" } - }, - "result": { "item": "computercraft:speaker" } -} 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 fa9e47af2..000000000 --- a/src/main/resources/data/computercraft/recipes/wired_modem.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "###" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" } - }, - "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 f9579b354..000000000 --- a/src/main/resources/data/computercraft/recipes/wired_modem_full_from.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "crafting_shapeless", - "ingredients": [ - { "item": "computercraft:wired_modem_full" } - ], - "result": { "item": "computercraft:wired_modem" } -} 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 204170660..000000000 --- a/src/main/resources/data/computercraft/recipes/wired_modem_full_to.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "crafting_shapeless", - "ingredients": [ - { "item": "computercraft:wired_modem" } - ], - "result": { "item": "computercraft:wired_modem_full" } -} 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 3d3297d6c..000000000 --- a/src/main/resources/data/computercraft/recipes/wireless_modem_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#E#", - "###" - ], - "key": { - "#": { "tag": "forge:ingots/gold" }, - "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 3005edd7d..000000000 --- a/src/main/resources/data/computercraft/recipes/wireless_modem_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#E#", - "###" - ], - "key": { - "#": { "tag": "forge:stone" }, - "E": { "item": "minecraft:ender_pearl" } - }, - "result": { "item": "computercraft:wireless_modem_normal" } -} diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 15b477b6a..2085450bb 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -10,12 +10,18 @@ import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +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.util.math.Vec3d; +import net.minecraft.world.World; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.*; @@ -78,7 +84,7 @@ public void before() throws IOException ComputerCraft.logPeripheralErrors = true; Terminal term = new Terminal( 78, 20 ); - IWritableMount mount = new FileMount( new File( "test-files/mount" ), Long.MAX_VALUE ); + IWritableMount mount = new FileMount( new File( "test-files/mount" ), 10_000_000 ); // Remove any existing files List children = new ArrayList<>(); @@ -89,10 +95,11 @@ public void before() throws IOException try( WritableByteChannel channel = mount.openForWrite( "startup.lua" ); Writer writer = Channels.newWriter( channel, StandardCharsets.UTF_8.newEncoder(), -1 ) ) { - writer.write( "loadfile('test/mcfly.lua', nil, _ENV)('test/spec') cct_test.finish()" ); + 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 ILuaAPI() { @Override @@ -114,7 +121,7 @@ public void startup() try { computer.getAPIEnvironment().getFileSystem().mount( - "test-rom", "test", + "test-rom", "test-rom", BasicEnvironment.createMount( ComputerTestDelegate.class, "test-rom", "test" ) ); } @@ -416,4 +423,33 @@ 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 World getWorld() + { + return null; + } + + @Nonnull + @Override + public Vec3d getPosition() + { + return Vec3d.ZERO; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } } diff --git a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java index f06002743..c57226bc9 100644 --- a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java +++ b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java @@ -115,7 +115,7 @@ public static IMount createMount( Class klass, String path, String fallback ) while( baseFile != null && !wholeFile.exists() ) { baseFile = baseFile.getParentFile(); - wholeFile = new File( baseFile, "resources/" + fallback + "/" + path ); + wholeFile = new File( baseFile, "src/" + fallback + "/resources/" + path ); } if( !wholeFile.exists() ) throw new IllegalStateException( "Cannot find ROM mount at " + file ); diff --git a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java index cf1c61529..fbc36dcb8 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java @@ -16,6 +16,10 @@ 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; @@ -25,10 +29,11 @@ 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 { - if( ZIP_FILE.exists() ) return; ZIP_FILE.getParentFile().mkdirs(); try( ZipOutputStream stream = new ZipOutputStream( new FileOutputStream( ZIP_FILE ) ) ) @@ -36,7 +41,7 @@ public static void before() throws IOException stream.putNextEntry( new ZipEntry( "dir/" ) ); stream.closeEntry(); - stream.putNextEntry( new ZipEntry( "dir/file.lua" ) ); + stream.putNextEntry( new ZipEntry( "dir/file.lua" ).setLastModifiedTime( MODIFY_TIME ) ); stream.write( "print('testing')".getBytes( StandardCharsets.UTF_8 ) ); stream.closeEntry(); } @@ -83,4 +88,21 @@ public void opensFileFromDir() throws IOException 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/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/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index d1b0ad599..81e5afb3c 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -13,7 +13,7 @@ -- -- @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 +-- @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. @@ -224,7 +224,7 @@ expect_mt.ne = expect_mt.not_equals function expect_mt:type(exp_type) local actual_type = type(self.value) if exp_type ~= actual_type then - fail(("Expected value of type %s\n got %s"):format(exp_type, actual_type)) + fail(("Expected value of type %s\nbut got %s"):format(exp_type, actual_type)) end return self @@ -238,8 +238,8 @@ local function matches(eq, exact, left, right) -- 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 + 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 @@ -273,7 +273,7 @@ end -- @throws If they are not equivalent function expect_mt:same(value) if not matches({}, true, self.value, value) then - fail(("Expected %s\n but got %s"):format(format(value), format(self.value))) + fail(("Expected %s\nbut got %s"):format(format(value), format(self.value))) end return self @@ -356,32 +356,49 @@ function expect_mt:called_with_matching(...) return called_with_check(matches, self, ...) end -local expect = setmetatable( { - --- 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 - error = function(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 - __call = function(_, value) - return setmetatable({ value = value }, expect_mt) - 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 + fail(("Expected value of type string\nbut got %s"):format(actual_type)) + end + if not self.value:find(pattern) then + fail(("Expected %q\n to match pattern %q"):format(self.value, pattern)) + end + + 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 } @@ -390,7 +407,8 @@ local test_stack = { n = 0 } local tests_locked = false --- The list of tests that we'll run -local test_list, test_map, test_count = { }, { }, 0 +local test_list = {} +local test_map, test_count = {}, 0 --- Add a new test to our queue. -- diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua index ad1bfb41c..5288aa9c8 100644 --- a/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -125,6 +125,21 @@ describe("The fs library", 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() @@ -134,4 +149,44 @@ describe("The fs library", function() 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 } + 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 } + + 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.modification - now >= 1000 then + fail(("Expected modification time (%d) to be within 1000ms of now (%d"):format(attributes.modification, now)) + end + 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 index a6774a48c..ecaf1d307 100644 --- a/src/test/resources/test-rom/spec/apis/http_spec.lua +++ b/src/test/resources/test-rom/spec/apis/http_spec.lua @@ -1,19 +1,19 @@ describe("The http library", function() describe("http.checkURL", function() it("accepts well formed domains", function() - expect({ http.checkURL("https://google.com")}):same({ true }) + 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'" }) + 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() - expect({ http.checkURL("http://localhost")}):same({ false, "Domain not permitted" }) - expect({ http.checkURL("http://127.0.0.1")}):same({ false, "Domain not permitted" }) + 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/peripheral_spec.lua b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua index 8fca583e1..c3fb5675f 100644 --- a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua +++ b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua @@ -1,4 +1,6 @@ describe("The peripheral library", function() + local it_modem = peripheral.getType("top") == "modem" and it or pending + describe("peripheral.isPresent", function() it("validates arguments", function() peripheral.isPresent("") @@ -26,6 +28,11 @@ describe("The peripheral library", function() 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("^peripheral_spec.lua:%d+: bad argument #1 %(number expected, got boolean%)$") + end) end) describe("peripheral.wrap", function() diff --git a/src/test/resources/test-rom/spec/apis/settings_spec.lua b/src/test/resources/test-rom/spec/apis/settings_spec.lua index b54e24e67..40af033d1 100644 --- a/src/test/resources/test-rom/spec/apis/settings_spec.lua +++ b/src/test/resources/test-rom/spec/apis/settings_spec.lua @@ -1,4 +1,18 @@ 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) @@ -13,6 +27,30 @@ describe("The settings library", function() 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() @@ -20,6 +58,43 @@ describe("The settings library", 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() @@ -27,17 +102,73 @@ describe("The settings library", 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, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(settings.load, 1):eq("bad argument #1 (expected string, got number)") + end) + + it("defaults to .settings", function() + local s = stub(fs, "open") + settings.load() + expect(s):called_with(".settings", "r") end) end) describe("settings.save", function() it("validates arguments", function() - expect.error(settings.save, nil):eq("bad argument #1 (expected string, got nil)") + 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/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua index ab881d60b..bdef2dbd2 100644 --- a/src/test/resources/test-rom/spec/apis/textutils_spec.lua +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -70,6 +70,69 @@ describe("The textutils library", function() 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) + 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() + it("basic objects", function() + expect(textutils.unserializeJSON([[{ a: 1, b:2 }]], { nbt_style = true })):same { a = 1, b = 2 } + end) + + it("suffixed numbers", function() + expect(textutils.unserializeJSON("1b", { nbt_style = true })):eq(1) + 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() 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 index 36f076f60..125e43640 100644 --- a/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua +++ b/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua @@ -1,31 +1,53 @@ describe("cc.expect", function() local e = require("cc.expect") - it("checks a single type", function() - expect(e.expect(1, "test", "string")):eq(true) - expect(e.expect(1, 2, "number")):eq(true) + 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)") + 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):eq("expect_spec.lua:27: bad argument #1 to 'worker' (expected string, got nil)") + end) end) - it("checks multiple types", function() - expect(e.expect(1, "test", "string", "number")):eq(true) - expect(e.expect(1, 2, "string", "number")):eq(true) + 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.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) + 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("includes the function name", function() - local function worker() - expect(e.expect(1, nil, "string")):eq(true) - end - local function trampoline() - worker() - 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(trampoline):eq("expect_spec.lua:26: bad argument #1 to 'worker' (expected string, got nil)") + 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) 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..2949c1a75 --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua @@ -0,0 +1,208 @@ +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) return pp.render(pp.pretty(x), 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("{ n = 3, 1, 2, 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) + end) + + it("shows numbers", function() + expect(pretty(123)):eq("123") + end) + + it("shows strings", function() + expect(pretty("hello\nworld")):eq('"hello\\nworld"') + end) + + it("shows functions", function() + expect(pretty(pretty)):eq(tostring(pretty)) + 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 index ffcd3b7f3..6b2c0aaa1 100644 --- 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 @@ -22,7 +22,7 @@ describe("cc.shell.completion", function() local spec = c.build( function() return { "a", "b", "c" } end, nil, - { c.choice, { "d", "e", "f"} } + { c.choice, { "d", "e", "f" } } ) expect(spec(shell, 1, "")):same { "a", "b", "c" } 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 index 0c12b18a7..ba714629f 100644 --- a/src/test/resources/test-rom/spec/programs/command/exec_spec.lua +++ b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua @@ -15,7 +15,7 @@ describe("The exec program", function() it("runs a command", function() stub(_G, "commands", { - exec = function() return true, {"Hello World!"} end, + exec = function() return true, { "Hello World!" } end, }) expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) @@ -24,7 +24,7 @@ describe("The exec program", function() it("reports command failures", function() stub(_G, "commands", { - exec = function() return false, {"Hello World!"} end, + exec = function() return false, { "Hello World!" } end, }) expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) diff --git a/src/test/resources/test-rom/spec/programs/delete_spec.lua b/src/test/resources/test-rom/spec/programs/delete_spec.lua index 5036f7eae..1eec95cc4 100644 --- a/src/test/resources/test-rom/spec/programs/delete_spec.lua +++ b/src/test/resources/test-rom/spec/programs/delete_spec.lua @@ -39,7 +39,7 @@ describe("The rm program", 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 = "/rom/startup.lua: Access denied\n" } diff --git a/src/test/resources/test-rom/spec/programs/edit_spec.lua b/src/test/resources/test-rom/spec/programs/edit_spec.lua index 7ca0b04f2..e58938e23 100644 --- a/src/test/resources/test-rom/spec/programs/edit_spec.lua +++ b/src/test/resources/test-rom/spec/programs/edit_spec.lua @@ -2,7 +2,7 @@ local capture = require "test_helpers".capture_program describe("The edit program", function() - it("displays its usage when given no argument", function() + it("displays its usage when given no argument", function() expect(capture(stub, "edit")) :matches { ok = true, output = "Usage: edit \n", error = "" } 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 index 5b13d59a9..192ba7007 100644 --- a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua +++ b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua @@ -49,17 +49,17 @@ describe("The pastebin program", function() it("upload a program to pastebin", function() setup_request() - local file = fs.open( "testup", "w" ) + local file = fs.open("testup", "w") file.close() - - expect(capture(stub, "pastebin", "put", "testup" )) + + 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" )) + expect(capture(stub, "pastebin", "put", "nothing")) :matches { ok = true, output = "No such file\n", error = "" } 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 index 73206e7fb..7c5d47da7 100644 --- a/src/test/resources/test-rom/spec/programs/id_spec.lua +++ b/src/test/resources/test-rom/spec/programs/id_spec.lua @@ -1,7 +1,7 @@ local capture = require "test_helpers".capture_program describe("The id program", function() - + it("displays computer id", function() local id = os.getComputerID() diff --git a/src/test/resources/test-rom/spec/programs/motd_spec.lua b/src/test/resources/test-rom/spec/programs/motd_spec.lua index 3781e2e16..72becbf30 100644 --- a/src/test/resources/test-rom/spec/programs/motd_spec.lua +++ b/src/test/resources/test-rom/spec/programs/motd_spec.lua @@ -7,7 +7,7 @@ describe("The motd program", function() file.write("Hello World!") file.close() settings.set("motd.path", "/modt_check.txt") - + expect(capture(stub, "motd")) :matches { ok = true, output = "Hello World!\n", error = "" } 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 index f52961a13..68762e79f 100644 --- a/src/test/resources/test-rom/spec/programs/peripherals_spec.lua +++ b/src/test/resources/test-rom/spec/programs/peripherals_spec.lua @@ -2,7 +2,8 @@ local capture = require "test_helpers".capture_program describe("The peripherals program", function() it("says when there are no peripherals", function() - expect(capture(stub, "peripherals" )) + 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/set_spec.lua b/src/test/resources/test-rom/spec/programs/set_spec.lua index 64dba1447..8d74d951e 100644 --- a/src/test/resources/test-rom/spec/programs/set_spec.lua +++ b/src/test/resources/test-rom/spec/programs/set_spec.lua @@ -1,29 +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() - settings.clear() - settings.set("Test", "Hello World!") - settings.set("123", 456) - + setup() + expect(capture(stub, "set")) - :matches { ok = true, output = '"123" is 456\n"Test" is "Hello World!"\n', error = "" } + :matches { ok = true, output = '"test" is "Hello World!"\n"test.defined" is 456\n', error = "" } end) - it("displays a single settings", function() - settings.clear() - settings.set("Test", "Hello World!") - settings.set("123", 456) - - expect(capture(stub, "set Test")) - :matches { ok = true, output = '"Test" is "Hello World!"\n', error = "" } + it("displays a single setting", function() + setup() + + expect(capture(stub, "set test")) + :matches { ok = true, output = 'test is "Hello World!"\n', error = "" } end) - it("set a setting", function() - expect(capture(stub, "set Test Hello")) - :matches { ok = true, output = '"Test" set to "Hello"\n', error = "" } + it("displays a single setting with description", function() + setup() - expect(settings.get("Test")):eq("Hello") + 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/time_spec.lua b/src/test/resources/test-rom/spec/programs/time_spec.lua index e9c1eff31..91f82fef0 100644 --- a/src/test/resources/test-rom/spec/programs/time_spec.lua +++ b/src/test/resources/test-rom/spec/programs/time_spec.lua @@ -5,7 +5,7 @@ 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) diff --git a/tools/check-lines.py b/tools/check-lines.py new file mode 100644 index 000000000..956e87d46 --- /dev/null +++ b/tools/check-lines.py @@ -0,0 +1,29 @@ +import pathlib, sys + +problems = False + +# Skip images and files without extensions +exclude = [ "*.png", "**/data/json-parsing/*.json" ] + +for path in pathlib.Path("src").glob("**/*"): + # Ideally we'd use generated as a glob, but .match("generated/**/*.json") doesn't work! + if path.is_dir() or path.suffix == "" or any(path.match(x) for x in exclude) or path.parts[1] == "generated": + continue + + with path.open(encoding="utf-8") as file: + has_dos, has_trailing, needs_final = False, False, False + for i, line in enumerate(file): + if len(line) >= 2 and line[-2] == "\r" and line[-1] == "\n" and not has_line: + print("%s has contains '\\r\\n' on line %d" % (path, i + 1)) + problems = has_dos = True + + if len(line) >= 2 and line[-2] in " \t" and line[-1] == "\n" and not has_trailing: + print("%s has trailing whitespace on line %d" % (path, i + 1)) + problems = has_trailing = True + + if line is not None and len(line) >= 1 and line[-1] != "\n": + print("%s should end with '\\n'" % path) + problems = True + +if problems: + sys.exit(1) diff --git a/tools/disk_recipe.json b/tools/disk_recipe.json deleted file mode 100644 index c6a67ab7a..000000000 --- a/tools/disk_recipe.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "${dye}" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": ${colour} } } -} diff --git a/tools/pocket_upgrade_advancement.json b/tools/pocket_upgrade_advancement.json deleted file mode 100644 index 2fd25329f..000000000 --- a/tools/pocket_upgrade_advancement.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:${path}" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_${pocket_family}" }, - { "item": "${upgrade_item}" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:${path}" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/tools/pocket_upgrade_recipe.json b/tools/pocket_upgrade_recipe.json deleted file mode 100644 index 354015b2a..000000000 --- a/tools/pocket_upgrade_recipe.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_${pocket_family}", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "${upgrade_item}" }, - "T": { "item": "computercraft:pocket_computer_${pocket_family}" } - }, - "result": { "item": "computercraft:pocket_computer_${pocket_family}", "nbt": { "Upgrade": "${upgrade_id}" } } -} diff --git a/tools/recipes.lua b/tools/recipes.lua deleted file mode 100644 index d2c007523..000000000 --- a/tools/recipes.lua +++ /dev/null @@ -1,136 +0,0 @@ ---- Generates impostor recipes and advancements for several dynamic recipes. --- --- Namely: --- - Turtle upgrades --- - Pocket upgrades --- - Disk (each colour) --- --- Note, this is largely intended for the recipe book, as that requires a fixed --- set of recipes. - ---- All turtle upgrades, and an optional item for this upgrade. -local turtle_upgrades = { - { "computercraft:wireless_modem_normal" }, - { "computercraft:wireless_modem_advanced" }, - { "computercraft:speaker" }, - { "minecraft:crafting_table" }, - { "minecraft:diamond_sword" }, - { "minecraft:diamond_shovel" }, - { "minecraft:diamond_pickaxe" }, - { "minecraft:diamond_axe" }, - { "minecraft:diamond_hoe" }, -} - ---- All pocket upgrades, and an optional item for this upgrade. -local pocket_upgrades = { - { "computercraft:wireless_modem_normal" }, - { "computercraft:wireless_modem_advanced" }, - { "computercraft:speaker" }, -} - ---- All dye/disk colours -local colours = { - { 0x111111, "minecraft:black_dye" }, - { 0xcc4c4c, "minecraft:red_dye" }, - { 0x57A64E, "minecraft:green_dye" }, - { 0x7f664c, "minecraft:brown_dye" }, - { 0x3366cc, "minecraft:blue_dye" }, - { 0xb266e5, "minecraft:purple_dye" }, - { 0x4c99b2, "minecraft:cyan_dye" }, - { 0x999999, "minecraft:light_gray_dye" }, - { 0x4c4c4c, "minecraft:gray_dye" }, - { 0xf2b2cc, "minecraft:pink_dye" }, - { 0x7fcc19, "minecraft:lime_dye" }, - { 0xdede6c, "minecraft:yellow_dye" }, - { 0x99b2f2, "minecraft:light_blue_dye" }, - { 0xe57fd8, "minecraft:magenta_dye" }, - { 0xf2b233, "minecraft:orange_dye" }, - { 0xf0f0f0, "minecraft:white_dye" }, -} - ---- Read the provided file into a string, exiting the program if not found. --- --- @tparam string file The file to read --- @treturn string The file's contents -local function read_all(file) - local h, e = io.open(file, "rb") - if not h then - io.stderr:write("Cannot open " .. file .. ": " .. tostring(e)) - os.exit(1) - end - - local c = h:read "*a" - h:close() - return c -end - ---- Write the provided string into a file, exiting on failure. --- --- @tparam string file The file to read --- @tparam string contents The new contents -local function write_all(file, contents) - local h, e = io.open(file, "wb") - if not h then - io.stderr:write("Cannot open " .. file .. ": " .. tostring(e)) - os.exit(1) - end - - h:write(contents) - h:close() -end - ---- Format template strings of the form `${key}` using the given substituion --- table. -local function template(str, subs) - return str:gsub("%$%{([^}]+)%}", function(k) - return subs[k] or error("Unknown key " .. k) - end) -end - --- Write turtle upgrades -local turtle_recipe = read_all "tools/turtle_upgrade_recipe.json" -local turtle_advance = read_all "tools/turtle_upgrade_advancement.json" -for _, turtle_family in ipairs { "normal", "advanced" } do - for _, upgrade in ipairs(turtle_upgrades) do - local upgrade_id, upgrade_item = upgrade[1], upgrade[2] or upgrade[1] - local path = ("generated/turtle_%s/%s"):format(turtle_family, (upgrade_id:gsub(":", "_"))) - local keys = { - upgrade_id = upgrade_id, upgrade_item = upgrade_item, - turtle_family = turtle_family, - path = path, - } - - write_all("src/main/resources/data/computercraft/recipes/" .. path .. ".json", template(turtle_recipe, keys)) - write_all("src/main/resources/data/computercraft/advancements/recipes/" .. path .. ".json", template(turtle_advance, keys)) - end -end - --- Write pocket upgrades -local pocket_recipe = read_all "tools/pocket_upgrade_recipe.json" -local pocket_advance = read_all "tools/pocket_upgrade_advancement.json" -for _, pocket_family in ipairs { "normal", "advanced" } do - for _, upgrade in ipairs(pocket_upgrades) do - local upgrade_id, upgrade_item = upgrade[1], upgrade[2] or upgrade[1] - local path = ("generated/pocket_%s/%s"):format(pocket_family, (upgrade_id:gsub(":", "_"))) - local keys = { - upgrade_id = upgrade_id, upgrade_item = upgrade_item, - pocket_family = pocket_family, - path = path, - } - - write_all("src/main/resources/data/computercraft/recipes/" .. path .. ".json", template(pocket_recipe, keys)) - write_all("src/main/resources/data/computercraft/advancements/recipes/" .. path .. ".json", template(pocket_advance, keys)) - end -end - --- Write disk recipe -local disk_recipe = read_all "tools/disk_recipe.json" -for i, colour in ipairs(colours) do - local path = ("generated/disk/disk_%s"):format(i) - local keys = { - dye = colour[2], colour = colour[1], - path = path, - } - - write_all("src/main/resources/data/computercraft/recipes/" .. path .. ".json", template(disk_recipe, keys)) -end diff --git a/tools/turtle_upgrade_advancement.json b/tools/turtle_upgrade_advancement.json deleted file mode 100644 index c671f4874..000000000 --- a/tools/turtle_upgrade_advancement.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:${path}" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_${turtle_family}" }, - { "item": "${upgrade_item}" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:${path}" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/tools/turtle_upgrade_recipe.json b/tools/turtle_upgrade_recipe.json deleted file mode 100644 index d81b346cd..000000000 --- a/tools/turtle_upgrade_recipe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_${turtle_family}", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "${upgrade_item}" }, - "T": { "item": "computercraft:turtle_${turtle_family}" } - }, - "result": { "item": "computercraft:turtle_${turtle_family}", "nbt": { "RightUpgrade": "${upgrade_id}" } } -}