diff --git a/.github/workflows/wai-formal-verification.yml b/.github/workflows/wai-formal-verification.yml index 79285a0c2..8b4c92936 100644 --- a/.github/workflows/wai-formal-verification.yml +++ b/.github/workflows/wai-formal-verification.yml @@ -22,6 +22,15 @@ name: wai formal verification (integer core) # The proofs are bounded (small symbolic CDFs, fixed-length symbolic streams, # explicit unwind limits). Bounded is not universal, and the job claims only # what it checks. +# +# It also checks the integer operator set (wai/extensions/integer-operators.md): +# the harnesses of its test plan, in wai/wai-ops/src/proofs/, which the host +# includes beside the operator set's sources. They prove the roundings, the +# requantisation, a 32-bit fabric's limb product and epilogue, the soundness of +# the bound rules against the interpreter, the stage operators' totality and +# refusal order, the plans, and the graph form's parse. Each harness states its +# window. The harnesses run in shards; the first job holds the shards to +# covering every harness exactly once. # One run per branch at a time. A push supersedes the run before it. # @@ -55,10 +64,13 @@ on: - 'wai/wai-rs/src/wai_video_policy.rs' - 'wai/wai-rs/src/staged/predict.rs' - 'wai/wai-rs/src/staged/wir1_arith.rs' - # Not verified by any harness, but #[path]-included because int_transform's - # IGDN dispatches to it, so it must still compile under the model checker - # (its cfg(kani) branches are compiled nowhere else). + # Verified by K10 as the fast path of the reference IGDN, and #[path]-included + # because int_transform's IGDN dispatches to it, so it must also compile under + # the model checker (its cfg(kani) branches are compiled nowhere else). - 'wai/wai-rs/src/int_kernels.rs' + # The integer operator set: its sources, which the host includes module by + # module, and its harnesses (src/proofs/). + - 'wai/wai-ops/src/**' - '.github/workflows/wai-formal-verification.yml' push: branches: @@ -72,19 +84,66 @@ on: - 'wai/wai-rs/src/staged/predict.rs' - 'wai/wai-rs/src/staged/wir1_arith.rs' - 'wai/wai-rs/src/int_kernels.rs' + - 'wai/wai-ops/src/**' - '.github/workflows/wai-formal-verification.yml' jobs: - kani: + # Every harness the host compiles runs in exactly one shard of the matrix below: + # one no shard runs would be compiled and never checked. No toolchain is needed; + # the script reads the included sources and this file. + shards: + name: every harness in one shard runs-on: linux + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Every harness runs in exactly one shard + run: python3 -I wai/wai-verify/check_shards.py . + + kani: + name: kani (${{ matrix.shard }}) + runs-on: ${{ matrix.os }} + timeout-minutes: 120 + strategy: + fail-fast: false + # Each shard is a list of `--harness` filters: a harness runs when its full name + # contains one. The integer operator set's harnesses (K1–K33 of its test plan) + # are in proofs::, split so that no shard runs much past an hour; the two 512-bit + # isqrt harnesses and the longest stage harnesses have shards of their own. + # Harnesses gated by cfg(kani_open) are not compiled here. + # + # Each shard runs where its memory fits. The rans64 totality proof (k26) peaks at + # about 28 GiB of resident memory and takes about 690 s of verification (measured + # with /usr/bin/time -l on a 256 GB host); the linux runner has 15 GiB, shared by + # two jobs, and CBMC ran out of memory there. It has a shard of its own on the + # macos runner. Every other shard has run to completion on the linux runner. + matrix: + include: + - { shard: integer-core, os: linux, harness: "rans:: int_entropy:: int_transform:: wai_video_policy:: staged_predict:: staged_wir1_arith::" } + - { shard: arith, os: linux, harness: "proofs::arith::k01 proofs::arith::k03 proofs::arith::k13_isqrt_u128 proofs::arith::k17 proofs::arith::k32 proofs::limb::" } + - { shard: isqrt512, os: linux, harness: "proofs::arith::k13_isqrt_i512 proofs::arith::k13_isqrt_ceil_i512" } + - { shard: stage, os: linux, harness: "proofs::stage::k23 proofs::stage::k27 proofs::stage::k28 proofs::stage::k29_residual_step_32bit_identity_registered proofs::stage::k30" } + - { shard: stage-long, os: linux, harness: "proofs::stage::k29_residual_step_32bit_identity_every_range" } + - { shard: rans64-t2, os: macos, harness: "proofs::stage::k26" } + - { shard: sound, os: linux, harness: "proofs::sound::" } + - { shard: plan, os: linux, harness: "proofs::plan::" } steps: - uses: actions/checkout@v4 # dtolnay/rust-toolchain cannot help — it calls `rustup`, which is absent - # on this runner image. + # on the linux runner's image. The macOS runner executes on the host, which + # has rustup in ~/.cargo/bin, but launchd's PATH omits that directory: it + # is put first, so the host's install is found and left as it is. - name: Install rustup + toolchain + shell: bash run: | set -euo pipefail + export PATH="$HOME/.cargo/bin:$PATH" if ! command -v rustup >/dev/null; then curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | sh -s -- -y --profile minimal --default-toolchain 1.98.0 @@ -92,8 +151,11 @@ jobs: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" # Kani ships its own pinned nightly and a CBMC build; both are slow to - # fetch, so they are cached on the verifier version. + # fetch, so they are cached on the verifier version. Not on macOS: that + # runner's home is the host's own, where Kani is installed, and a restore + # would write over a live install. - name: Cache Kani toolchain + if: matrix.os != 'macos' uses: actions/cache@v4 with: path: | @@ -102,20 +164,41 @@ jobs: ~/.kani key: kani-0.67.0-${{ runner.os }} + # The same steps on every runner: Kani 0.67.0 unless that version is installed, + # then its setup unless it is set up. Setup fetches the release bundle (CBMC and + # the driver) and installs the pinned nightly, which the bundle's `toolchain` + # links to in ~/.rustup. Run again, it fetches and installs both again, so it is + # skipped when the bundle and its toolchain are both in place: on the macOS + # host, which is set up, it would rewrite a live install. The cache holds the + # bundle but not ~/.rustup, so a container sets up every time. - name: Install Kani + shell: bash run: | set -euo pipefail export PATH="$HOME/.cargo/bin:$PATH" - command -v cargo-kani >/dev/null || cargo install --locked kani-verifier --version 0.67.0 - # Idempotent; fetches the pinned nightly + CBMC on a cold cache. - cargo kani setup + if [ "$(cargo kani --version 2>/dev/null || true)" != "cargo-kani 0.67.0" ]; then + cargo install --locked kani-verifier --version 0.67.0 + fi + k="$HOME/.kani/kani-0.67.0" + if [ ! -x "$k/bin/kani-driver" ] || [ ! -x "$k/bin/cbmc" ] || [ ! -e "$k/toolchain/bin/rustc" ]; then + cargo kani setup + fi + cargo kani --version - - name: Verify the integer core + - name: Verify the shard's harnesses working-directory: wai/wai-verify + shell: bash run: | set -euo pipefail export PATH="$HOME/.cargo/bin:$PATH" # Every harness must verify. A failing harness is a real finding # about the decoder, so this job is allowed to be the thing that # blocks the merge. - cargo kani + # + # The harnesses are in the library. The crate's one binary, the + # `wai-verify` tool, needs the `cli` feature, and a target whose + # required features are off stops `cargo kani` from building any; + # `--lib` selects the library alone. + args=() + for f in ${{ matrix.harness }}; do args+=(--harness "$f"); done + cargo kani --lib "${args[@]}" diff --git a/.github/workflows/wai-jpegai-e2e.yml b/.github/workflows/wai-jpegai-e2e.yml index 8422b35e7..1890a3c91 100644 --- a/.github/workflows/wai-jpegai-e2e.yml +++ b/.github/workflows/wai-jpegai-e2e.yml @@ -23,6 +23,11 @@ name: WAI JPEG-AI whole decode (pinned inputs, required) # of samples differ from it at all (the test's bar); # - two decodes in one process are byte-identical and the reconstruction binding # verifies the second and rejects a one-byte change; +# - the bundle's bounds certificate (wai/extensions/integer-operators.md §8.5, +# §13.6.1: the two scale graphs) is byte for byte the one committed under the +# set's digest in wai/ops-conformance/certificates/, which is the listing digest +# the set-form pin below covers, from both certifiers (wai-verify and the +# independent tools/wai_ops_check.py), and its verdict meets acc32; # - the decoded pixels hash to WAI_JPEGAI_EXPECT_SHA256 below: the value measured # from these inputs on an Apple Silicon Mac (aarch64 macOS, native) and # reproduced by an x86_64 Linux build (glibc, run under QEMU user-mode @@ -108,6 +113,16 @@ on: - 'wai/wai-rs/tests/support/**' - 'wai/tools/wai_jpegai_fetch_e2e_inputs.sh' - 'wai/tools/jpegai-e2e-v1.sha256' + # The bounds certificate of the bundle's scale path (the step after the fetch): + # the certifier, and the certificate committed by digest. + - 'wai/wai-ops/src/**' + - 'wai/wai-ops/tests/goldens.rs' + - 'wai/wai-verify/Cargo.toml' + - 'wai/wai-verify/Cargo.lock' + - 'wai/wai-verify/src/bin/**' + - 'wai/ops-conformance/certificates/external.json' + - 'wai/ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json' + - 'wai/tools/wai_ops_check.py' - '.github/workflows/wai-jpegai-e2e.yml' pull_request: paths: @@ -133,6 +148,16 @@ on: - 'wai/wai-rs/tests/support/**' - 'wai/tools/wai_jpegai_fetch_e2e_inputs.sh' - 'wai/tools/jpegai-e2e-v1.sha256' + # The bounds certificate of the bundle's scale path (the step after the fetch): + # the certifier, and the certificate committed by digest. + - 'wai/wai-ops/src/**' + - 'wai/wai-ops/tests/goldens.rs' + - 'wai/wai-verify/Cargo.toml' + - 'wai/wai-verify/Cargo.lock' + - 'wai/wai-verify/src/bin/**' + - 'wai/ops-conformance/certificates/external.json' + - 'wai/ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json' + - 'wai/tools/wai_ops_check.py' - '.github/workflows/wai-jpegai-e2e.yml' # Weekly, independent of changes: the inputs live outside the repository, and # their disappearing should surface here, not at the next unrelated PR. @@ -165,6 +190,53 @@ jobs: shell: bash working-directory: wai run: tools/wai_jpegai_fetch_e2e_inputs.sh "$WAI_JPEGAI_DIR" + # The scale path's bounds certificate (integer-operators §8.5, §13.6.1). The + # bundle is not committed, so its certificate is, under the set's digest (the + # listing of norm.json and weights/*, as the set-form pin covers it), and + # listed in wai/ops-conformance/certificates/external.json. + - name: The bundle's bounds certificate is the committed one, and meets acc32 + shell: bash + working-directory: wai + run: | + set -euo pipefail + (cd wai-verify && cargo build --locked --release --features cli --bin wai-verify) + D="$WAI_JPEGAI_DIR" + M=(--member "norm.json=$D/norm.json") + for n in hs_y hs_uv hyp_y hyp_uv synth_y synth_uv mcm0_y mcm1_y mcm2_y mcm3_y icci; do + M+=(--member "weights/$n.json=$D/$n.json") + done + wai-verify/target/release/wai-verify bounds --capability wai.image.jpegai "${M[@]}" --profile acc32 \ + --out "${RUNNER_TEMP:-/tmp}/jpegai-bounds.json" \ + --check ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json + # The same certificate from the independent certifier (Python standard library + # only, sharing no code with wai-ops). + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: The independent certifier writes the same certificate, and it meets acc32 + shell: bash + working-directory: wai + run: | + set -euo pipefail + D="$WAI_JPEGAI_DIR" + M=(--member "norm.json=$D/norm.json") + for n in hs_y hs_uv hyp_y hyp_uv synth_y synth_uv mcm0_y mcm1_y mcm2_y mcm3_y icci; do + M+=(--member "weights/$n.json=$D/$n.json") + done + python3 -I tools/wai_ops_check.py certify --capability wai.image.jpegai --lowering jpegai-int/1 "${M[@]}" \ + --profile acc32 --out "${RUNNER_TEMP:-/tmp}/jpegai-bounds-py.json" \ + --check ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json + # The operator set's lowering of the bundle's scale path (integer-operators + # §13.6.1), run through the interpreter with every value held to its certified + # interval, against the legacy decoder's arithmetic on the same bundle. + - name: The scale path's lowering decodes as the legacy arithmetic does + shell: bash + working-directory: wai/wai-ops + run: | + set -euo pipefail + WAI_OPS_JPEGAI_BUNDLE="$WAI_JPEGAI_DIR" \ + cargo test --locked --release --test goldens -- --ignored --exact jpegai_scale_path_on_a_supplied_bundle + - name: Whole decode vs the reference, determinism, pinned pixel hash (missing input = failure) shell: bash working-directory: wai/wai-rs diff --git a/.github/workflows/wai-ops.yml b/.github/workflows/wai-ops.yml index 712fae639..9dc7da721 100644 --- a/.github/workflows/wai-ops.yml +++ b/.github/workflows/wai-ops.yml @@ -5,17 +5,23 @@ name: wai-ops integer operators # wai/ops-conformance/ from its inputs and requires the committed bytes: # # - Linux x86_64, Linux arm64 and macOS arm64, natively, debug and release: the -# unit tests, the goldens (every committed parameter set lowered, loaded and +# unit tests (the bound rules against hand-computed values among them), the +# goldens (every committed parameter set lowered, loaded through load step 8 and # decoded through the interpreter to its committed output digest), the step-8 -# test and the doc tests, each in the default build and with the `uncertified` -# switch, and `wai-ops vectors verify`, which also re-lowers every set and -# regenerates the whole corpus; -# - WASI (wasm32-wasip2) under wasmtime, a 32-bit target: the same unit tests, -# goldens and step-8 test in both builds, and the same `vectors verify`; +# and verdict tests and the doc tests; `wai-verify vectors verify`, which also +# re-lowers every set, recomputes its bounds certificate from the committed +# lowered graphs and regenerates the whole corpus, so every certificate is +# byte-identical on every leg; and `wai-verify bounds` on the falsification sets +# of integer-operators §14.3, which must exit 1, and on committed sets, which +# must exit 0 under their profile; +# - WASI (wasm32-wasip2) under wasmtime, a 32-bit target: the same tests, and the +# same `vectors verify`; # - a browser's engine (wasm32-unknown-unknown) under Node: the recomputation of # every vector file; # - the independent checker, tools/wai_ops_check.py: Python standard library only, -# sharing no code with wai-ops, rewrites every vector file and every lowered graph. +# sharing no code with wai-ops, rewrites every vector file and every lowered graph, +# and, as a second certifier, every certificate, the falsification sets' included +# (each must fail the profile it claims). # # There is no Windows leg: the Windows runner has been offline since 2026-08-28. @@ -33,6 +39,8 @@ on: pull_request: paths: - 'wai/wai-ops/**' + # The certifier, the lowerings and the corpus tool, and the Kani host they share. + - 'wai/wai-verify/**' - 'wai/ops-conformance/**' - 'wai/tools/wai_ops_*.py' # The text the checker is held to. @@ -52,6 +60,8 @@ on: - main paths: - 'wai/wai-ops/**' + # The certifier, the lowerings and the corpus tool, and the Kani host they share. + - 'wai/wai-verify/**' - 'wai/ops-conformance/**' - 'wai/tools/wai_ops_*.py' - 'wai/extensions/integer-operators.md' @@ -91,28 +101,66 @@ jobs: rustup default 1.98.0 echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - # Without the `uncertified` switch, load step 8 refuses every graph: the default - # build is what a decoder would link before the certifier exists. Its tests show - # that, and the doc tests that a graph runs only once loaded. - - name: Unit, step-8 and doc tests, default build + - name: Unit, goldens, step-8, verdict and doc tests, debug working-directory: wai/wai-ops shell: bash run: cargo test --locked - - name: Unit tests and goldens, debug + - name: Unit, goldens, step-8 and verdict tests, release working-directory: wai/wai-ops shell: bash - run: cargo test --locked --features uncertified + run: cargo test --locked --release - - name: Unit tests and goldens, release - working-directory: wai/wai-ops + - name: Build wai-verify, and its own tests (the witness through the interpreter; --check's path) + working-directory: wai/wai-verify shell: bash - run: cargo test --locked --release --features uncertified + run: | + set -euo pipefail + cargo build --locked --release --features cli --bin wai-verify + cargo test --locked --release --features cli --bin wai-verify - - name: Every vector file recomputed, every set re-lowered, the corpus regenerated - working-directory: wai/wai-ops + - name: Every vector file recomputed, every set re-lowered and certified, the corpus regenerated + working-directory: wai shell: bash - run: cargo run --locked --release --features uncertified --bin wai-ops -- vectors verify .. + run: wai-verify/target/release/wai-verify vectors verify . + + # The exit status of `wai-verify bounds` (0: the verdict meets the profile, 1: it + # fails it, 3: a difference from the committed certificate), on the sets whose + # verdict integer-operators §14.3 and the design's predictions fix. + - name: The falsification sets fail their profile; committed sets meet theirs + working-directory: wai + shell: bash + run: | + set -euo pipefail + V=wai-verify/target/release/wai-verify + C=ops-conformance/certificates/wai.neural.int_synth + T="${RUNNER_TEMP:-/tmp}" + bounds() { + local want=$1; shift + set +e; "$V" bounds "$@" --out "$T/cert.json"; local got=$?; set -e + [ "$got" = "$want" ] || { echo "::error::wai-verify bounds $* exited $got, not $want"; exit 1; } + } + # One unit past i64 under acc64, and a claim of acc32 one weight past it. + bounds 1 ops-conformance/sets/overflow_acc64/int_synth.json --capability wai.neural.int_synth --profile acc64 \ + --check $C/b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a.json + bounds 1 ops-conformance/sets/claim_acc32/int_synth.json --capability wai.neural.int_synth --profile acc32 \ + --check $C/76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac.json + # facade meets acc32; photo meets acc64 and fails acc32 (at node 6, convT.acc). + bounds 0 neural-conformance/vectors/facade/int_synth.json --capability wai.neural.int_synth --profile acc32 \ + --check $C/c6a362696d61605931ef4da98ae630362dcd73ea6be7864db6e61d6c5abbcd24.json + bounds 0 neural-conformance/vectors/photo/int_synth.json --capability wai.neural.int_synth --profile acc64 \ + --check $C/50868e72f5f1599569c413ed1f67ab8610fa0b3c17919162cbf370f49275125c.json + # With --witness, a node-local graph for each failing node: photo's node 6, whose + # input attains convT.acc's upper end. With --advise, the clamps that would let + # the overflow set meet acc64. + bounds 1 neural-conformance/vectors/photo/int_synth.json --capability wai.neural.int_synth --profile acc32 \ + --witness "$T/witness" + test -s "$T/witness/synth-6.json" + grep -q '"acc":"26172239136"' "$T/witness/synth-6.json" + bounds 1 ops-conformance/sets/overflow_acc64/int_synth.json --capability wai.neural.int_synth --advise acc64 + # A certificate that is not the committed one is exit 3. + bounds 3 neural-conformance/vectors/photo/int_synth.json --capability wai.neural.int_synth \ + --check $C/c6a362696d61605931ef4da98ae630362dcd73ea6be7864db6e61d6c5abbcd24.json wasip2: name: wasm32-wasip2 (wasmtime) @@ -144,7 +192,7 @@ jobs: # The tests read committed files through CARGO_MANIFEST_DIR/.., so the wai # directory is preopened at its own absolute path. - - name: Unit and step-8 tests, default build, under WASI + - name: Unit, goldens, step-8 and verdict tests, under WASI working-directory: wai/wai-ops shell: bash run: | @@ -153,27 +201,18 @@ jobs: CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime run --dir $W::$W" \ cargo test --locked --release --target wasm32-wasip2 - - name: Unit tests, goldens and step-8 test, under WASI - working-directory: wai/wai-ops + - name: Build wai-verify for wasm32-wasip2 + working-directory: wai/wai-verify shell: bash - run: | - set -euo pipefail - W=$(cd .. && pwd) - CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime run --dir $W::$W" \ - cargo test --locked --release --features uncertified --target wasm32-wasip2 + run: cargo build --locked --release --features cli --target wasm32-wasip2 --bin wai-verify - - name: Build the tool for wasm32-wasip2 - working-directory: wai/wai-ops - shell: bash - run: cargo build --locked --release --features uncertified --target wasm32-wasip2 --bin wai-ops - - - name: Every vector file recomputed, every set re-lowered, the corpus regenerated, under WASI + - name: Every vector file recomputed, every set re-lowered and certified, the corpus regenerated, under WASI working-directory: wai shell: bash run: | set -euo pipefail wasmtime --version - wasmtime run --dir .::/wai wai-ops/target/wasm32-wasip2/release/wai-ops.wasm vectors verify /wai + wasmtime run --dir .::/wai wai-verify/target/wasm32-wasip2/release/wai-verify.wasm vectors verify /wai node: name: wasm32 under Node @@ -219,7 +258,7 @@ jobs: python-version: '3.11' # Standard library only, so it needs nothing installed. - - name: wai_ops_check.py rewrites every vector file and every lowered graph + - name: wai_ops_check.py rewrites every vector file, every lowered graph and every certificate working-directory: wai shell: bash run: python3 -I tools/wai_ops_check.py ops-conformance diff --git a/.github/workflows/wai-sota-vectors.yml b/.github/workflows/wai-sota-vectors.yml index cd6b59da4..eaa3b589a 100644 --- a/.github/workflows/wai-sota-vectors.yml +++ b/.github/workflows/wai-sota-vectors.yml @@ -22,6 +22,12 @@ name: WAI mbt2018_mean integer decode (regenerated vectors) # - the Rust integer decode reproduces the export tool's integer reference # byte-for-byte (synthesis, hyper-decoder, the whole conditional bitstream, the # compact binary model, the eight-frame clip); +# - the regenerated set's bounds certificate (wai/extensions/integer-operators.md +# §8.5) is byte for byte the one committed under its set digest in +# wai/ops-conformance/certificates/, from both certifiers (wai-verify and the +# independent tools/wai_ops_check.py), and its verdict meets acc64. The set is +# not committed, so this job is where its certificate is checked; the set's +# three files have had the same digests on every run and machine recorded; # - on the pinned photograph, the integer decode costs at most 1 dB against the # same model's float decode (the bar CI enforces), measured by the Rust decoder # on its own output. Measured on an Apple Silicon Mac: 35.985 dB for the integer @@ -129,6 +135,15 @@ on: - 'wai/tools/requirements-sota-int.txt' # The wasm32 decode of the same vectors (the last steps below). - 'wai/wai-web/**' + # The bounds certificate of the regenerated set (the step after the + # regeneration): the certifier, and the certificate committed by digest. + - 'wai/wai-ops/src/**' + - 'wai/wai-verify/Cargo.toml' + - 'wai/wai-verify/Cargo.lock' + - 'wai/wai-verify/src/bin/**' + - 'wai/ops-conformance/certificates/external.json' + - 'wai/ops-conformance/certificates/wai.neural.int_hyper/f16fd09cd79b831d7d821e030c05e99e9fb5ea216574e699944ea4e55ac0a404.json' + - 'wai/tools/wai_ops_check.py' - '.github/workflows/wai-sota-vectors.yml' pull_request: paths: @@ -151,6 +166,15 @@ on: - 'wai/tools/requirements-sota-int.txt' # The wasm32 decode of the same vectors (the last steps below). - 'wai/wai-web/**' + # The bounds certificate of the regenerated set (the step after the + # regeneration): the certifier, and the certificate committed by digest. + - 'wai/wai-ops/src/**' + - 'wai/wai-verify/Cargo.toml' + - 'wai/wai-verify/Cargo.lock' + - 'wai/wai-verify/src/bin/**' + - 'wai/ops-conformance/certificates/external.json' + - 'wai/ops-conformance/certificates/wai.neural.int_hyper/f16fd09cd79b831d7d821e030c05e99e9fb5ea216574e699944ea4e55ac0a404.json' + - 'wai/tools/wai_ops_check.py' - '.github/workflows/wai-sota-vectors.yml' # Weekly, independent of changes: the job depends on artifacts fetched from # outside the repository (the checkpoint, the pinned wheels), and their @@ -228,6 +252,35 @@ jobs: # files differ between machines (see the header). It is not a list any # other run must reproduce, here or elsewhere. (cd "$WAI_SOTA_INT_DIR" && sha256sum *) + # The set's bounds certificate (integer-operators §8.5). The set is not + # committed, so its certificate is, under the set's digest, and listed in + # wai/ops-conformance/certificates/external.json. A regenerated set with other + # bytes has another digest, and --check fails on set_sha256 first. + - name: The regenerated set's bounds certificate is the committed one, and meets acc64 + shell: bash + working-directory: wai + run: | + set -euo pipefail + (cd wai-verify && cargo build --locked --release --features cli --bin wai-verify) + D="$WAI_SOTA_INT_DIR" + wai-verify/target/release/wai-verify bounds --capability wai.neural.int_hyper \ + --member h_s.whm="$D/int_hs_model.bin" --member g_s.whm="$D/int_synth_sota_model.bin" \ + --member entropy.json="$D/cond_entropy.json" --profile acc64 \ + --out "${RUNNER_TEMP:-/tmp}/int-hyper-bounds.json" \ + --check ops-conformance/certificates/wai.neural.int_hyper/f16fd09cd79b831d7d821e030c05e99e9fb5ea216574e699944ea4e55ac0a404.json + # The same certificate from the independent certifier (Python standard library + # only, sharing no code with wai-ops), which needs only the Python set up above. + - name: The independent certifier writes the same certificate, and it meets acc64 + shell: bash + working-directory: wai + run: | + set -euo pipefail + D="$WAI_SOTA_INT_DIR" + python3 -I tools/wai_ops_check.py certify --capability wai.neural.int_hyper --lowering whm1/1 \ + --member h_s.whm="$D/int_hs_model.bin" --member g_s.whm="$D/int_synth_sota_model.bin" \ + --member entropy.json="$D/cond_entropy.json" --profile acc64 \ + --out "${RUNNER_TEMP:-/tmp}/int-hyper-bounds-py.json" \ + --check ops-conformance/certificates/wai.neural.int_hyper/f16fd09cd79b831d7d821e030c05e99e9fb5ea216574e699944ea4e55ac0a404.json - name: Rust decodes every int_hyper vector byte-for-byte (missing input = failure), and the missing-input rule holds shell: bash working-directory: wai/wai-rs diff --git a/wai/ops-conformance/README.md b/wai/ops-conformance/README.md index 44fe269a3..4f68e4f95 100644 --- a/wai/ops-conformance/README.md +++ b/wai/ops-conformance/README.md @@ -5,7 +5,7 @@ Vectors for `wai-ops/1`, the integer operator set operators (§5), its stage operators (§5E), the `WHG1` graph form (§10), and the canonical lowerings of the registered integer network forms (§13). -**Provenance.** Generated here by `wai-ops vectors gen` from fixed SplitMix64 +**Provenance.** Generated here by `wai-verify vectors gen` from fixed SplitMix64 sequences: every graph, parameter, input and stream under `vectors/`, `stage/`, `graphs/` and `sets/` is generated integers, with no media. The lowered graphs under `certificates/` are those of the sets this corpus generates and of the parameter sets @@ -33,10 +33,26 @@ lowering conforms when it writes every lowered graph byte for byte. - `lower_
` — each lowering of §13 on a small set from `sets/`. - `sets//` — the small parameter sets the `lower_*` vectors lower, one per lowering, in their registered forms. -- `certificates///.whg1` — each lowered graph (§14.3). +- `certificates//.json` — each set's bounds certificate + (§8.5, §14.3), and beside it `certificates///.whg1`, + each lowered graph. - `certificates/index.json` — every set lowered here: its capability, its lowering, its members (the name in the set and the file, relative to `wai/`, that holds it), its digest, and the path of each lowered graph, in §13.0's role order. +- `certificates/falsification.json` — the two sets of §14.3 that a certifier must + reject, in the same form, each with `claim`, the profile it is checked against: + `overflow_acc64`, whose accumulator passes i64 by one unit, and `claim_acc32`, + whose pin claims `acc32` and whose accumulator passes i32 by one unit, one weight + past a set that meets it. Their members are under `sets/`. A sink refuses both + under the profile they are checked against (§8.6). +- `certificates/external.json` — the sets whose certificates are here although the + sets are not: the CI-regenerated `wai.neural.int_hyper` set and the `jpegai/v1` + bundle of the models root. Each entry gives the set's members (the name in the set, + then the file the job that holds it reads), its digest, the profile its verdict + meets, and that job's workflow, which certifies the set and requires these bytes. + Here, `vectors verify` and the independent checker check only what they can + without the set: that each such certificate is canonical, names its set, and meets + its profile. The job that holds the set certifies it with both certifiers. Files are compared as bytes; `.gitattributes` turns off line-ending conversion. @@ -57,9 +73,9 @@ In short: line ending with one line feed. - A graph vector's decodes list the graph's **data** inputs only; the decodes of one vector are one sequence, and a refused decode changes no state (§10.3). -- `load` is the outcome of load steps 1–8 (§10.5); every vector here loads or is - refused at steps 1–7 (see below). A vector whose load is refused has no decodes and - lists both profiles; one that loads lists exactly the profiles its verdict meets. +- `load` is the outcome of load steps 1–8 (§10.5), under every profile the vector + lists. A vector whose load is refused, at any step, has no decodes and lists both + profiles; one that loads lists exactly the profiles its verdict meets. - `at` is −1 for a refusal before any symbol or element, the symbol's index for `rans64_decode` (the number of symbols for a refusal after the last one), and, for `mans_decode`, the position whose step refuses, or, for a flush that belongs to no @@ -67,24 +83,26 @@ In short: - A vector of `graphs/lower_.jsonl` has the id `///…`: its graph is that role of the set `sets//` as lowered. -## What this corpus does not cover yet +## The vectors load step 8 decides -Load step 8 has no implementation in `wai-ops` yet: its bounds pass and verdict land -with the certifier. Until then the `uncertified` switch skips it, and the generator -writes no vector whose outcome depends on it; a generated case whose graph meets no -profile is dropped, and `vectors gen` reports the count. So these coverage classes -of §14.1 item 6, each a load refusal at step 8, are not here yet: +Whether a graph loads, and under which profiles, is the verdict of its bounds pass +(§8). Besides every other vector's `profiles`, these depend on it alone (§14.1 item +6), each in its operator's file, with an id that names the class: -- `sigmoid` and `elu` on an input range that reaches `−2^63`, refused at load (the - corpus has the decoding side, ranges that stop at `−(2^63 − 1)`); -- an `rq` whose `q` passes 64 bits while `y` fits, refused at load under `acc64` - (`conv`, `conv_transpose`, `rescale`, `chscale`, `mul`, `gram`, `apply`); -- a `lut16` whose input range passes `[−32767, 32767]`, and a `check` range that no - value of its producer can meet (§8.1); -- a graph refused at step 8 in `graphs/load.jsonl`. - -The independent checker already runs step 8 and recomputes every vector's -`profiles` from its own bounds pass, so these vectors are checked the day they land. +- `sigmoid/step8/…`, `elu/step8/…`: an input range that reaches `−2^63`, refused at + load (`exp.negx` passes i64); the ranges that stop at `−(2^63 − 1)` decode; +- `/step8_q/…`: an `rq` whose `q` passes 64 bits, refused under `acc64`; with a + `post` bias (`conv`, `conv_transpose`, `rescale`) `y` fits while `q` does not, and + beside each, the same graph one unit inside, which decodes; +- `l2norm/eps/…` and `layernorm_c`'s cases with `ε = 2^64 − 1`, which load under + `acc64` only; +- `/acc32_param/…`: a graph that fails `acc32` by one parameter condition of + §7.2 alone (`rq.mult`, `rq.shift`, `rq.post_bias`, `weights`, `chscale.m`, + `chscale.s`, `igdn.gamma`, `igdn.shift`, `leaky.a`), every interval within i32; +- `lut16/step8/…`: an input range that reaches `±32768` (§5.6); +- `graphs/load.jsonl`, `load/step8/…`: a `check` range its producer cannot meet, one + that its producer meets at one value (loads, under `acc64` only), and an + accumulator past i64. ## The lowered sets @@ -96,18 +114,25 @@ lowering's latent channel count, which the initial latent fixes, is the entry's ## Generation and verification - cd wai/wai-ops - cargo run --release --features uncertified --bin wai-ops -- vectors gen .. + cd wai/wai-verify + cargo run --release --features cli --bin wai-verify -- vectors gen .. -writes every file here but this README and `.gitattributes`. +writes every file here but this README, `.gitattributes`, and `external.json` with +the certificates it lists. - cargo run --release --features uncertified --bin wai-ops -- vectors verify .. + cargo run --release --features cli --bin wai-verify -- vectors verify .. -recomputes every vector file from its inputs, re-lowers every set, and regenerates -the corpus, and requires every byte to equal the committed one. The same check runs -built for `wasm32-wasip2` under a WASI runtime, and, for the vector files, -`wai-ops/node/verify.mjs` runs the recomputation as a `wasm32-unknown-unknown` -module under a browser's engine. +recomputes every vector file from its inputs, re-lowers every set and recomputes its +certificate from the committed lowered graphs, checks that each falsification set +fails the profile it claims, and regenerates the corpus, and requires every byte to +equal the committed one. The same check runs built for `wasm32-wasip2` under a WASI +runtime, and, for the vector files, `wai-ops/node/verify.mjs` runs the recomputation +as a `wasm32-unknown-unknown` module under a browser's engine. + + wai-verify bounds --capability [--profile acc32|acc64] [--check ] + +certifies one set (or `WHG1` graphs on their own), and exits 0 when its verdict meets +the profile, 1 when it does not, and 3 when `--check` finds a difference. python3 -I tools/wai_ops_check.py ops-conformance @@ -117,4 +142,16 @@ decides, and the disagreement is a bug in one of them. It rewrites every vector from its inputs, `load` (steps 1–8) and `profiles` from its own bounds pass and verdict (§8.1–§8.5) included; re-lowers every set and requires each lowered graph, and that each loads; and requires each lowering vector's graph to be the role its id -names. Every byte must equal the committed one. +names. It is also a second certifier (§1): from each set's lowered graphs it writes +the set's certificate (§8.5) and requires the committed bytes, for every set of +`index.json` and both falsification sets, each of which must fail the profile it +claims. Every byte must equal the committed one. + + python3 -I tools/wai_ops_check.py ops-conformance --external = + python3 -I tools/wai_ops_check.py certify --capability --lowering \ + --member =... [--profile acc32|acc64] [--out ] [--check ] + +certify an external set from the directory that holds its files, and one set (or +`WHG1` graphs on their own, with `--whg1 =`), with the exit statuses of +`wai-verify bounds`: 0, 1, 3 as above; 2 when a graph is malformed or refused at load; +4 when the lowering refuses the set; 5 for usage. diff --git a/wai/ops-conformance/certificates/external.json b/wai/ops-conformance/certificates/external.json new file mode 100644 index 000000000..9eaa134da --- /dev/null +++ b/wai/ops-conformance/certificates/external.json @@ -0,0 +1 @@ +{"format":"wai-ops-external/1","sets":[{"capability":"wai.neural.int_hyper","lowering":"whm1/1","members":{"entropy.json":"cond_entropy.json","g_s.whm":"int_synth_sota_model.bin","h_s.whm":"int_hs_model.bin"},"name":"sota","note":"regenerated from pinned inputs by the job that certifies it; not committed","profile":"acc64","set_sha256":"f16fd09cd79b831d7d821e030c05e99e9fb5ea216574e699944ea4e55ac0a404","workflow":".github/workflows/wai-sota-vectors.yml"},{"capability":"wai.image.jpegai","lowering":"jpegai-int/1","members":{"norm.json":"norm.json","weights/hs_uv.json":"hs_uv.json","weights/hs_y.json":"hs_y.json","weights/hyp_uv.json":"hyp_uv.json","weights/hyp_y.json":"hyp_y.json","weights/icci.json":"icci.json","weights/mcm0_y.json":"mcm0_y.json","weights/mcm1_y.json":"mcm1_y.json","weights/mcm2_y.json":"mcm2_y.json","weights/mcm3_y.json":"mcm3_y.json","weights/synth_uv.json":"synth_uv.json","weights/synth_y.json":"synth_y.json"},"name":"jpegai/v1","note":"the models root's jpegai/v1, the files tools/jpegai-e2e-v1.sha256 pins; not committed","profile":"acc32","set_sha256":"3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37","workflow":".github/workflows/wai-jpegai-e2e.yml"}]} diff --git a/wai/ops-conformance/certificates/falsification.json b/wai/ops-conformance/certificates/falsification.json new file mode 100644 index 000000000..706f669a0 --- /dev/null +++ b/wai/ops-conformance/certificates/falsification.json @@ -0,0 +1 @@ +{"format":"wai-ops-falsification/1","sets":[{"capability":"wai.neural.int_synth","claim":"acc64","lowering":"int_synth/1","members":{"int_synth.json":"ops-conformance/sets/overflow_acc64/int_synth.json"},"name":"overflow_acc64","note":"fails acc64 by one unit (section 14.3)","roles":["ops-conformance/certificates/wai.neural.int_synth/b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a/synth.whg1"],"set_sha256":"b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a","synthetic":true},{"capability":"wai.neural.int_synth","claim":"acc32","lowering":"int_synth/1","members":{"int_synth.json":"ops-conformance/sets/claim_acc32/int_synth.json"},"name":"claim_acc32","note":"its pin claims acc32, which it fails by one weight (section 14.3)","roles":["ops-conformance/certificates/wai.neural.int_synth/76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac/synth.whg1"],"set_sha256":"76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac","synthetic":true}]} diff --git a/wai/ops-conformance/certificates/wai.audio.int_codec/132958122b251869ad6725d24a2bb96e2733daaf3e09ef65ebc7af6f46030855.json b/wai/ops-conformance/certificates/wai.audio.int_codec/132958122b251869ad6725d24a2bb96e2733daaf3e09ef65ebc7af6f46030855.json new file mode 100644 index 000000000..ebabe0051 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.audio.int_codec/132958122b251869ad6725d24a2bb96e2733daaf3e09ef65ebc7af6f46030855.json @@ -0,0 +1 @@ +{"capability":"wai.audio.int_codec","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"df85aecd5c4f8f46aee4019e06b4c1312167913f35af19d76ae02f3200cb5724","inputs":[{"hi":"56322496561155","kind":"data","lo":"-56322496561155","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"62","hi":"1674467822763138150","lo":"-1674467822763138150"},"convT.term":{"bits":"58","hi":"115292150460684285","lo":"-115292150460684285"},"rq.p":{"bits":"72","hi":"1433912187050582698800","lo":"-1433912187050582698800"},"rq.q":{"bits":"48","hi":"85467826548253","lo":"-85467826548254"},"rq.t":{"bits":"62","hi":"1674467822763138150","lo":"-1674467822763138150"},"rq.y":{"bits":"48","hi":"85467826548630","lo":"-85467826547877"}},"k_c":"0","mac":{"a_bits":["47"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"90358937651","lo":"-90358937651","policy":"check","result":{"bits":"48","hi":"85467826548630","lo":"-85467826547877"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"78","hi":"92256202836030637609896","lo":"0"},"igdn.gx2":{"bits":"91","hi":"716006665008630596860158695","lo":"0"},"igdn.r":{"bits":"40","hi":"303737062005","lo":"4492"},"igdn.term":{"bits":"75","hi":"10925394668710794019472","lo":"0"},"igdn.x2":{"bits":"74","hi":"8164737613417305397801","lo":"0"},"igdn.xr":{"bits":"76","hi":"27445358248007716050255","lo":"-27445358248007716050255"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"47","hi":"56322496561155","lo":"-56322496561155","policy":"check","result":{"bits":"64","hi":"6700526916017508801","lo":"-6700526916017508802"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"63","hi":"2479992168580776960","lo":"-2479992168580776960"},"convT.term":{"bits":"58","hi":"115292150460684285","lo":"-115292150460684285"},"rq.p":{"bits":"73","hi":"4525835326594099668150","lo":"-4525835326594099668150"},"rq.q":{"bits":"49","hi":"269760806953555","lo":"-269760806953556"},"rq.t":{"bits":"63","hi":"2479992168580776960","lo":"-2479992168580776960"},"rq.y":{"bits":"49","hi":"269760806953545","lo":"-269760806953566"}},"k_c":"0","mac":{"a_bits":["47"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"81573816262","lo":"-81573816262","policy":"check","result":{"bits":"49","hi":"269760806953545","lo":"-269760806953566"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{"igdn.N":{"bits":"78","hi":"82876116900136935033537","lo":"0"},"igdn.gx2":{"bits":"91","hi":"878532307127631369540324100","lo":"0"},"igdn.r":{"bits":"40","hi":"287882123272","lo":"4282"},"igdn.term":{"bits":"75","hi":"13405339159051992333073","lo":"0"},"igdn.x2":{"bits":"74","hi":"6654287499546535652644","lo":"0"},"igdn.xr":{"bits":"76","hi":"23483643428904562249264","lo":"-23483643428904562249264"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"47","hi":"56322496561155","lo":"-56322496561155","policy":"check","result":{"bits":"64","hi":"5733311384009902892","lo":"-5733311384009902893"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{"convT.acc":{"bits":"63","hi":"2356251643635919425","lo":"-2356251643635919425"},"convT.term":{"bits":"58","hi":"115292150460684285","lo":"-115292150460684285"},"rq.p":{"bits":"73","hi":"3704757748641084149520","lo":"-3704757748641084149520"},"rq.q":{"bits":"49","hi":"220820769586627","lo":"-220820769586628"},"rq.t":{"bits":"63","hi":"2356251643635919425","lo":"-2356251643635919425"},"rq.y":{"bits":"49","hi":"220820769585117","lo":"-220820769588138"}},"k_c":"0","mac":{"a_bits":["47"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"85865415932","lo":"-85865415932","policy":"check","result":{"bits":"49","hi":"220820769585117","lo":"-220820769588138"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"5","intermediates":{"igdn.N":{"bits":"78","hi":"95091748353359683349418","lo":"0"},"igdn.gx2":{"bits":"91","hi":"792907893981090854391939456","lo":"0"},"igdn.r":{"bits":"40","hi":"308369499713","lo":"4304"},"igdn.term":{"bits":"75","hi":"12098814300248578710814","lo":"0"},"igdn.x2":{"bits":"74","hi":"7372869653175359428624","lo":"0"},"igdn.xr":{"bits":"76","hi":"26478275353599499627516","lo":"-26478275353599499627516"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"47","hi":"56322496561155","lo":"-56322496561155","policy":"check","result":{"bits":"64","hi":"6464422693749877838","lo":"-6464422693749877839"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"6","intermediates":{"convT.acc":{"bits":"62","hi":"2277738083429669355","lo":"-2277738083429669355"},"convT.term":{"bits":"58","hi":"115292150460684285","lo":"-115292150460684285"},"rq.p":{"bits":"74","hi":"8983399001046615936120","lo":"-8983399001046615936120"},"rq.q":{"bits":"50","hi":"535452306332982","lo":"-535452306332983"},"rq.t":{"bits":"62","hi":"2277738083429669355","lo":"-2277738083429669355"},"rq.y":{"bits":"50","hi":"535452306332898","lo":"-535452306333067"}},"k_c":"0","mac":{"a_bits":["47"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"50","hi":"535452306332898","lo":"-535452306333067","policy":"derived","result":{"bits":"50","hi":"535452306332898","lo":"-535452306333067"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"7","intermediates":{},"npu_flags":[],"op":"crop","out":[{"bits":"50","hi":"281483566907399","lo":"-281483566907400","policy":"check","result":{"bits":"50","hi":"535452306332898","lo":"-535452306333067"},"tensor":"8"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"8","intermediates":{"rq.p":{"bits":"64","hi":"9223372036854745081","lo":"-9223372036854775800"},"rq.q":{"bits":"52","hi":"2251799813685240","lo":"-2251799813685248"},"rq.t":{"bits":"50","hi":"281483566907399","lo":"-281483566907400"},"rq.y":{"bits":"52","hi":"2251799813685240","lo":"-2251799813685248"}},"npu_flags":[],"op":"rescale","out":[{"bits":"52","hi":"2251799813685240","lo":"-2251799813685248","policy":"derived","result":{"bits":"52","hi":"2251799813685240","lo":"-2251799813685248"},"tensor":"9"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"9","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"16","hi":"32767","lo":"-32768","policy":"derived","result":{"bits":"16","hi":"32767","lo":"-32768"},"tensor":"10"}],"saturated":false}],"scalars":[{"hi":"67108864","index":"0","lo":"1"}]}],"lowering":"wam1/1","set_sha256":"132958122b251869ad6725d24a2bb96e2733daaf3e09ef65ebc7af6f46030855","verdict":{"acc32":false,"acc32_first_failure":{"bits":"47","graph":"g_s","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","crop_scalar","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.audio.int_codec/8eca5bfdc1d8098ccdcfb8e3a7280c0550c4120ea87f224f0d4269e8fd4d1896.json b/wai/ops-conformance/certificates/wai.audio.int_codec/8eca5bfdc1d8098ccdcfb8e3a7280c0550c4120ea87f224f0d4269e8fd4d1896.json new file mode 100644 index 000000000..7e8939c40 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.audio.int_codec/8eca5bfdc1d8098ccdcfb8e3a7280c0550c4120ea87f224f0d4269e8fd4d1896.json @@ -0,0 +1 @@ +{"capability":"wai.audio.int_codec","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"8f68d90b0e57279d06062705c1f46e3fffefa44c90f829f0219e9eba646a4c4e","inputs":[{"hi":"2882303761517117","kind":"data","lo":"-2882303761517117","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"63","hi":"3963167672086035875","lo":"-3963167672086035875"},"convT.term":{"bits":"61","hi":"1152921504606846800","lo":"-1152921504606846800"},"rq.p":{"bits":"75","hi":"12198630094680818423250","lo":"-12198630094680818423250"},"rq.q":{"bits":"63","hi":"2978181175459184185","lo":"-2978181175459184186"},"rq.t":{"bits":"63","hi":"3963167672086035875","lo":"-3963167672086035875"},"rq.y":{"bits":"63","hi":"2978181175459184134","lo":"-2978181175459184237"}},"k_c":"0","mac":{"a_bits":["53"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"121438811524","lo":"-121438811524","policy":"check","result":{"bits":"63","hi":"2978181175459184134","lo":"-2978181175459184237"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"73","hi":"3027966488820337357051","lo":"0"},"igdn.gx2":{"bits":"85","hi":"12387803353263739970163840","lo":"0"},"igdn.r":{"bits":"37","hi":"55026961471","lo":"189"},"igdn.term":{"bits":"73","hi":"3024366053042905266153","lo":"0"},"igdn.x2":{"bits":"75","hi":"14747384944361595202576","lo":"0"},"igdn.xr":{"bits":"74","hi":"6682408802815178791804","lo":"-6682408802815178791804"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"53","hi":"4013651887230102","lo":"-4013651887230102","policy":"check","result":{"bits":"64","hi":"6525789846499198038","lo":"-6525789846499198039"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"64","hi":"5209720149624672396","lo":"-5209720149624672396"},"convT.term":{"bits":"62","hi":"1537228672809129066","lo":"-1537228672809129066"},"rq.p":{"bits":"72","hi":"1604593806084399097968","lo":"-1604593806084399097968"},"rq.q":{"bits":"60","hi":"391746534688573998","lo":"-391746534688573999"},"rq.t":{"bits":"64","hi":"5209720149624672396","lo":"-5209720149624672396"},"rq.y":{"bits":"60","hi":"391746534688574460","lo":"-391746534688573537"}},"k_c":"0","mac":{"a_bits":["53"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"60","hi":"391746534688574460","lo":"-391746534688573537","policy":"derived","result":{"bits":"60","hi":"391746534688574460","lo":"-391746534688573537"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"crop","out":[{"bits":"50","hi":"281483566907399","lo":"-281483566907400","policy":"check","result":{"bits":"60","hi":"391746534688574460","lo":"-391746534688573537"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{"rq.p":{"bits":"64","hi":"9223372036854743545","lo":"-9223372036854775800"},"rq.q":{"bits":"54","hi":"9007199254740960","lo":"-9007199254740992"},"rq.t":{"bits":"50","hi":"281483566907399","lo":"-281483566907400"},"rq.y":{"bits":"54","hi":"9007199254740960","lo":"-9007199254740992"}},"npu_flags":[],"op":"rescale","out":[{"bits":"54","hi":"9007199254740960","lo":"-9007199254740992","policy":"derived","result":{"bits":"54","hi":"9007199254740960","lo":"-9007199254740992"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"16","hi":"32767","lo":"-32768","policy":"derived","result":{"bits":"16","hi":"32767","lo":"-32768"},"tensor":"6"}],"saturated":false}],"scalars":[{"hi":"67108864","index":"0","lo":"1"}]}],"lowering":"wam1/1","set_sha256":"8eca5bfdc1d8098ccdcfb8e3a7280c0550c4120ea87f224f0d4269e8fd4d1896","verdict":{"acc32":false,"acc32_first_failure":{"bits":"53","graph":"g_s","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","crop_scalar","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json b/wai/ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json new file mode 100644 index 000000000..b52caf219 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.image.jpegai/3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37.json @@ -0,0 +1 @@ +{"capability":"wai.image.jpegai","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"6a1be7ff1daa769bda87fc4a87702e1dd13ab5fd50593b09f0ae46709c2f55c3","inputs":[{"hi":"32","kind":"data","lo":"-31","max_h":"4","max_w":"4","policy":"check","tensor":"0"}],"name":"hs_y","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"7","hi":"32","lo":"-31","policy":"derived","result":{"bits":"7","hi":"32","lo":"-31"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"1","intermediates":{"conv.acc":{"bits":"19","hi":"167129","lo":"-166779"},"conv.term":{"bits":"13","hi":"4064","lo":"-4096"},"rq.p":{"bits":"19","hi":"167129","lo":"-166779"},"rq.q":{"bits":"15","hi":"12573","lo":"-12580"},"rq.t":{"bits":"19","hi":"167129","lo":"-166779"},"rq.y":{"bits":"15","hi":"12573","lo":"-12580"}},"k_c":"524287","mac":{"a_bits":["7"],"w_bits":"8"},"npu_flags":[],"op":"conv","out":[{"bits":"15","hi":"12573","lo":"-12580","policy":"derived","result":{"bits":"15","hi":"12573","lo":"-12580"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"15","hi":"12573","lo":"0","policy":"derived","result":{"bits":"15","hi":"12573","lo":"0"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"8","hi":"127","lo":"0","policy":"derived","result":{"bits":"8","hi":"127","lo":"0"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{"conv.acc":{"bits":"24","hi":"2217039","lo":"-4447271"},"conv.term":{"bits":"15","hi":"16129","lo":"-16256"},"rq.p":{"bits":"24","hi":"2217039","lo":"-4447271"},"rq.q":{"bits":"15","hi":"2055","lo":"-9051"},"rq.t":{"bits":"24","hi":"2217039","lo":"-4447271"},"rq.y":{"bits":"15","hi":"2055","lo":"-9051"}},"k_c":"132104","mac":{"a_bits":["8"],"w_bits":"8"},"npu_flags":[],"op":"conv","out":[{"bits":"15","hi":"2055","lo":"-9051","policy":"derived","result":{"bits":"15","hi":"2055","lo":"-9051"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"13","hi":"2055","lo":"0","policy":"derived","result":{"bits":"13","hi":"2055","lo":"0"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"6","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"8","hi":"127","lo":"0","policy":"derived","result":{"bits":"8","hi":"127","lo":"0"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"7","intermediates":{"conv.acc":{"bits":"20","hi":"272927","lo":"-268224"},"conv.term":{"bits":"15","hi":"16129","lo":"-16256"},"rq.p":{"bits":"20","hi":"272927","lo":"-268224"},"rq.q":{"bits":"17","hi":"45403","lo":"-47149"},"rq.t":{"bits":"20","hi":"272927","lo":"-268224"},"rq.y":{"bits":"17","hi":"45403","lo":"-47149"}},"k_c":"132104","mac":{"a_bits":["8"],"w_bits":"8"},"npu_flags":[],"op":"conv","out":[{"bits":"17","hi":"45403","lo":"-47149","policy":"derived","result":{"bits":"17","hi":"45403","lo":"-47149"},"tensor":"8"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"8","intermediates":{},"npu_flags":[],"op":"pixel_shuffle","out":[{"bits":"17","hi":"45403","lo":"-47149","policy":"derived","result":{"bits":"17","hi":"45403","lo":"-47149"},"tensor":"9"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"9","intermediates":{},"npu_flags":[],"op":"abs","out":[{"bits":"17","hi":"47149","lo":"0","policy":"derived","result":{"bits":"17","hi":"47149","lo":"0"},"tensor":"10"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"10","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"13","hi":"3967","lo":"0","policy":"derived","result":{"bits":"13","hi":"3967","lo":"0"},"tensor":"11"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"11","intermediates":{"rq.p":{"bits":"13","hi":"3973","lo":"-687"},"rq.q":{"bits":"13","hi":"3973","lo":"-687"},"rq.t":{"bits":"13","hi":"3973","lo":"-687"},"rq.y":{"bits":"13","hi":"3973","lo":"-687"}},"npu_flags":[],"op":"rescale","out":[{"bits":"13","hi":"3973","lo":"-687","policy":"derived","result":{"bits":"13","hi":"3973","lo":"-687"},"tensor":"12"}],"saturated":false}],"scalars":[]},{"graph_sha256":"c782be5dbe90eb45ff1440442d6f9cfab8867619bf7053c8407255692e82f4ba","inputs":[{"hi":"32","kind":"data","lo":"-31","max_h":"4","max_w":"4","policy":"check","tensor":"0"}],"name":"hs_uv","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"7","hi":"32","lo":"-31","policy":"derived","result":{"bits":"7","hi":"32","lo":"-31"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"1","intermediates":{"conv.acc":{"bits":"18","hi":"125851","lo":"-125590"},"conv.term":{"bits":"13","hi":"4064","lo":"-4096"},"rq.p":{"bits":"18","hi":"125851","lo":"-125590"},"rq.q":{"bits":"15","hi":"8663","lo":"-8678"},"rq.t":{"bits":"18","hi":"125851","lo":"-125590"},"rq.y":{"bits":"15","hi":"8663","lo":"-8678"}},"k_c":"524287","mac":{"a_bits":["7"],"w_bits":"8"},"npu_flags":[],"op":"conv","out":[{"bits":"15","hi":"8663","lo":"-8678","policy":"derived","result":{"bits":"15","hi":"8663","lo":"-8678"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"15","hi":"8663","lo":"0","policy":"derived","result":{"bits":"15","hi":"8663","lo":"0"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"8","hi":"127","lo":"0","policy":"derived","result":{"bits":"8","hi":"127","lo":"0"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{"conv.acc":{"bits":"23","hi":"1406906","lo":"-2765738"},"conv.term":{"bits":"15","hi":"16129","lo":"-16256"},"rq.p":{"bits":"23","hi":"1406906","lo":"-2765738"},"rq.q":{"bits":"16","hi":"10991","lo":"-28596"},"rq.t":{"bits":"23","hi":"1406906","lo":"-2765738"},"rq.y":{"bits":"16","hi":"10991","lo":"-28596"}},"k_c":"132104","mac":{"a_bits":["8"],"w_bits":"8"},"npu_flags":[],"op":"conv","out":[{"bits":"16","hi":"10991","lo":"-28596","policy":"derived","result":{"bits":"16","hi":"10991","lo":"-28596"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"15","hi":"10991","lo":"0","policy":"derived","result":{"bits":"15","hi":"10991","lo":"0"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"6","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"8","hi":"127","lo":"0","policy":"derived","result":{"bits":"8","hi":"127","lo":"0"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"7","intermediates":{"conv.acc":{"bits":"19","hi":"261017","lo":"-260731"},"conv.term":{"bits":"15","hi":"16129","lo":"-16256"},"rq.p":{"bits":"19","hi":"261017","lo":"-260731"},"rq.q":{"bits":"16","hi":"18225","lo":"-18225"},"rq.t":{"bits":"19","hi":"261017","lo":"-260731"},"rq.y":{"bits":"16","hi":"18225","lo":"-18225"}},"k_c":"132104","mac":{"a_bits":["8"],"w_bits":"8"},"npu_flags":[],"op":"conv","out":[{"bits":"16","hi":"18225","lo":"-18225","policy":"derived","result":{"bits":"16","hi":"18225","lo":"-18225"},"tensor":"8"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"8","intermediates":{},"npu_flags":[],"op":"pixel_shuffle","out":[{"bits":"16","hi":"18225","lo":"-18225","policy":"derived","result":{"bits":"16","hi":"18225","lo":"-18225"},"tensor":"9"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"9","intermediates":{},"npu_flags":[],"op":"abs","out":[{"bits":"16","hi":"18225","lo":"0","policy":"derived","result":{"bits":"16","hi":"18225","lo":"0"},"tensor":"10"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"10","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"13","hi":"3967","lo":"0","policy":"derived","result":{"bits":"13","hi":"3967","lo":"0"},"tensor":"11"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"11","intermediates":{"rq.p":{"bits":"13","hi":"3970","lo":"-82"},"rq.q":{"bits":"13","hi":"3970","lo":"-82"},"rq.t":{"bits":"13","hi":"3970","lo":"-82"},"rq.y":{"bits":"13","hi":"3970","lo":"-82"}},"npu_flags":[],"op":"rescale","out":[{"bits":"13","hi":"3970","lo":"-82","policy":"derived","result":{"bits":"13","hi":"3970","lo":"-82"},"tensor":"12"}],"saturated":false}],"scalars":[]}],"lowering":"jpegai-int/1","set_sha256":"3e243dc11566922f5cb7f4c628afd440b18d56a08b99b07cc33d5c8522aeec37","verdict":{"acc32":true,"acc64":true,"npu":true,"npu_flags":[],"npu_reasons":[]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.image.jpegai/60020d0657c4561db336a42f2d359b254a3f12348e8122aeb7bbb91d63b180ad.json b/wai/ops-conformance/certificates/wai.image.jpegai/60020d0657c4561db336a42f2d359b254a3f12348e8122aeb7bbb91d63b180ad.json new file mode 100644 index 000000000..95b0078b4 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.image.jpegai/60020d0657c4561db336a42f2d359b254a3f12348e8122aeb7bbb91d63b180ad.json @@ -0,0 +1 @@ +{"capability":"wai.image.jpegai","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"855f51089f67930d3f2f6a9de47ecbd246bbe138b1e6935ac8970546fa998b43","inputs":[{"hi":"32","kind":"data","lo":"-31","max_h":"4","max_w":"4","policy":"check","tensor":"0"}],"name":"hs_y","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"7","hi":"32","lo":"-31","policy":"derived","result":{"bits":"7","hi":"32","lo":"-31"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"1","intermediates":{"conv.acc":{"bits":"20","hi":"325039","lo":"-323175"},"conv.term":{"bits":"14","hi":"4096","lo":"-4096"},"rq.p":{"bits":"20","hi":"325039","lo":"-323175"},"rq.q":{"bits":"17","hi":"38494","lo":"-38383"},"rq.t":{"bits":"20","hi":"325039","lo":"-323175"},"rq.y":{"bits":"17","hi":"38494","lo":"-38383"}},"k_c":"524287","mac":{"a_bits":["7"],"w_bits":"9"},"npu_flags":[],"op":"conv","out":[{"bits":"17","hi":"38494","lo":"-38383","policy":"derived","result":{"bits":"17","hi":"38494","lo":"-38383"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"17","hi":"38494","lo":"0","policy":"derived","result":{"bits":"17","hi":"38494","lo":"0"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"8","hi":"127","lo":"0","policy":"derived","result":{"bits":"8","hi":"127","lo":"0"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{"conv.acc":{"bits":"18","hi":"119507","lo":"-113009"},"conv.term":{"bits":"15","hi":"15748","lo":"-15367"},"rq.p":{"bits":"18","hi":"119507","lo":"-113009"},"rq.q":{"bits":"10","hi":"270","lo":"-442"},"rq.t":{"bits":"18","hi":"119507","lo":"-113009"},"rq.y":{"bits":"10","hi":"270","lo":"-442"}},"k_c":"136365","mac":{"a_bits":["8"],"w_bits":"8"},"npu_flags":[],"op":"conv","out":[{"bits":"10","hi":"270","lo":"-442","policy":"derived","result":{"bits":"10","hi":"270","lo":"-442"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"10","hi":"270","lo":"0","policy":"derived","result":{"bits":"10","hi":"270","lo":"0"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"6","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"8","hi":"127","lo":"0","policy":"derived","result":{"bits":"8","hi":"127","lo":"0"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"7","intermediates":{"conv.acc":{"bits":"16","hi":"31800","lo":"-31877"},"conv.term":{"bits":"15","hi":"16256","lo":"-16256"},"rq.p":{"bits":"16","hi":"31800","lo":"-31877"},"rq.q":{"bits":"15","hi":"15017","lo":"-15177"},"rq.t":{"bits":"16","hi":"31800","lo":"-31877"},"rq.y":{"bits":"15","hi":"15017","lo":"-15177"}},"k_c":"132104","mac":{"a_bits":["8"],"w_bits":"9"},"npu_flags":[],"op":"conv","out":[{"bits":"15","hi":"15017","lo":"-15177","policy":"derived","result":{"bits":"15","hi":"15017","lo":"-15177"},"tensor":"8"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"8","intermediates":{},"npu_flags":[],"op":"pixel_shuffle","out":[{"bits":"15","hi":"15017","lo":"-15177","policy":"derived","result":{"bits":"15","hi":"15017","lo":"-15177"},"tensor":"9"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"9","intermediates":{},"npu_flags":[],"op":"abs","out":[{"bits":"15","hi":"15177","lo":"0","policy":"derived","result":{"bits":"15","hi":"15177","lo":"0"},"tensor":"10"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"10","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"13","hi":"3967","lo":"0","policy":"derived","result":{"bits":"13","hi":"3967","lo":"0"},"tensor":"11"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"11","intermediates":{"rq.p":{"bits":"13","hi":"3971","lo":"-686"},"rq.q":{"bits":"13","hi":"3971","lo":"-686"},"rq.t":{"bits":"13","hi":"3971","lo":"-686"},"rq.y":{"bits":"13","hi":"3971","lo":"-686"}},"npu_flags":[],"op":"rescale","out":[{"bits":"13","hi":"3971","lo":"-686","policy":"derived","result":{"bits":"13","hi":"3971","lo":"-686"},"tensor":"12"}],"saturated":false}],"scalars":[]},{"graph_sha256":"75bff95e2652c45176ec50c0f252a579d82cae89074dc75cc23d5e55a163a2e5","inputs":[{"hi":"32","kind":"data","lo":"-31","max_h":"4","max_w":"4","policy":"check","tensor":"0"}],"name":"hs_uv","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"7","hi":"32","lo":"-31","policy":"derived","result":{"bits":"7","hi":"32","lo":"-31"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"1","intermediates":{"conv.acc":{"bits":"19","hi":"181871","lo":"-182589"},"conv.term":{"bits":"13","hi":"4032","lo":"-4096"},"rq.p":{"bits":"19","hi":"181871","lo":"-182589"},"rq.q":{"bits":"16","hi":"22733","lo":"-22824"},"rq.t":{"bits":"19","hi":"181871","lo":"-182589"},"rq.y":{"bits":"16","hi":"22733","lo":"-22824"}},"k_c":"524287","mac":{"a_bits":["7"],"w_bits":"8"},"npu_flags":[],"op":"conv","out":[{"bits":"16","hi":"22733","lo":"-22824","policy":"derived","result":{"bits":"16","hi":"22733","lo":"-22824"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"16","hi":"22733","lo":"0","policy":"derived","result":{"bits":"16","hi":"22733","lo":"0"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"8","hi":"127","lo":"0","policy":"derived","result":{"bits":"8","hi":"127","lo":"0"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{"conv.acc":{"bits":"18","hi":"88914","lo":"-107059"},"conv.term":{"bits":"15","hi":"15367","lo":"-15748"},"rq.p":{"bits":"18","hi":"88914","lo":"-107059"},"rq.q":{"bits":"8","hi":"69","lo":"-105"},"rq.t":{"bits":"18","hi":"88914","lo":"-107059"},"rq.y":{"bits":"8","hi":"69","lo":"-105"}},"k_c":"136365","mac":{"a_bits":["8"],"w_bits":"8"},"npu_flags":[],"op":"conv","out":[{"bits":"8","hi":"69","lo":"-105","policy":"derived","result":{"bits":"8","hi":"69","lo":"-105"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"8","hi":"69","lo":"0","policy":"derived","result":{"bits":"8","hi":"69","lo":"0"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"6","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"8","hi":"69","lo":"0","policy":"derived","result":{"bits":"8","hi":"69","lo":"0"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"7","intermediates":{"conv.acc":{"bits":"16","hi":"17422","lo":"-17319"},"conv.term":{"bits":"15","hi":"8832","lo":"-8832"},"rq.p":{"bits":"16","hi":"17422","lo":"-17319"},"rq.q":{"bits":"15","hi":"8425","lo":"-8660"},"rq.t":{"bits":"16","hi":"17422","lo":"-17319"},"rq.y":{"bits":"15","hi":"8425","lo":"-8660"}},"k_c":"243148","mac":{"a_bits":["8"],"w_bits":"9"},"npu_flags":[],"op":"conv","out":[{"bits":"15","hi":"8425","lo":"-8660","policy":"derived","result":{"bits":"15","hi":"8425","lo":"-8660"},"tensor":"8"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"8","intermediates":{},"npu_flags":[],"op":"pixel_shuffle","out":[{"bits":"15","hi":"8425","lo":"-8660","policy":"derived","result":{"bits":"15","hi":"8425","lo":"-8660"},"tensor":"9"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"9","intermediates":{},"npu_flags":[],"op":"abs","out":[{"bits":"15","hi":"8660","lo":"0","policy":"derived","result":{"bits":"15","hi":"8660","lo":"0"},"tensor":"10"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"10","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"13","hi":"3967","lo":"0","policy":"derived","result":{"bits":"13","hi":"3967","lo":"0"},"tensor":"11"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"11","intermediates":{"rq.p":{"bits":"13","hi":"3961","lo":"-684"},"rq.q":{"bits":"13","hi":"3961","lo":"-684"},"rq.t":{"bits":"13","hi":"3961","lo":"-684"},"rq.y":{"bits":"13","hi":"3961","lo":"-684"}},"npu_flags":[],"op":"rescale","out":[{"bits":"13","hi":"3961","lo":"-684","policy":"derived","result":{"bits":"13","hi":"3961","lo":"-684"},"tensor":"12"}],"saturated":false}],"scalars":[]}],"lowering":"jpegai-int/1","set_sha256":"60020d0657c4561db336a42f2d359b254a3f12348e8122aeb7bbb91d63b180ad","verdict":{"acc32":true,"acc64":true,"npu":true,"npu_flags":[],"npu_reasons":[]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_hyper/13e8b0d18e001eb9f0160309a02755b35a14f71ba0bcaa13f373e32b931ab818.json b/wai/ops-conformance/certificates/wai.neural.int_hyper/13e8b0d18e001eb9f0160309a02755b35a14f71ba0bcaa13f373e32b931ab818.json new file mode 100644 index 000000000..bf845724b --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_hyper/13e8b0d18e001eb9f0160309a02755b35a14f71ba0bcaa13f373e32b931ab818.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_hyper","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"c3a28ef54396808853b68f2ffef651e004fd6ff88a048c76ee614f8ed8f1c67d","inputs":[{"hi":"3222701620144925","kind":"data","lo":"-3222701620144925","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"h_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"63","hi":"2565270489635360300","lo":"-2565270489635360300"},"convT.term":{"bits":"60","hi":"512409557603043075","lo":"-512409557603043075"},"rq.p":{"bits":"81","hi":"667884053450150128295400","lo":"-667884053450150128295400"},"rq.q":{"bits":"57","hi":"39808991757044203","lo":"-39808991757044204"},"rq.t":{"bits":"63","hi":"2565270489635360300","lo":"-2565270489635360300"},"rq.y":{"bits":"57","hi":"39808991757044187","lo":"-39808991757044220"}},"k_c":"0","mac":{"a_bits":["53"],"w_bits":"9"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"55","hi":"14081484025732482","lo":"-14081484025732482","policy":"check","result":{"bits":"57","hi":"39808991757044187","lo":"-39808991757044220"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"leaky.p":{"bits":"64","hi":"-655","lo":"-9223372036854775710"}},"npu_flags":[],"op":"leaky","out":[{"bits":"52","hi":"1601279867509509","lo":"-140737488355328","policy":"check","result":{"bits":"55","hi":"14081484025732482","lo":"-140737488355328"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"conv.acc":{"bits":"63","hi":"3416621454807471888","lo":"-3185392888939409270"},"conv.term":{"bits":"59","hi":"254603498934011931","lo":"-256204778801521440"},"rq.p":{"bits":"81","hi":"606252144183947426750496","lo":"-559793427871021368369507"},"rq.q":{"bits":"57","hi":"36135443698403085","lo":"-33366288415850483"},"rq.t":{"bits":"63","hi":"3416621454807471888","lo":"-3185392888939409270"},"rq.y":{"bits":"57","hi":"36135443698403074","lo":"-33366288415850488"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"9"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"57","hi":"36135443698403074","lo":"-33366288415850488","policy":"derived","result":{"bits":"57","hi":"36135443698403074","lo":"-33366288415850488"},"tensor":"3"}],"saturated":false}],"scalars":[]},{"graph_sha256":"f8ad13b9e3ed1624e4b1cfe2ffe6ac8b391738f01263ec118324a1c8a8bac136","inputs":[{"hi":"1601279867509509","kind":"data","lo":"-1601279867509509","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"63","hi":"2717371935163636773","lo":"-2717371935163636773"},"convT.term":{"bits":"59","hi":"256204778801521440","lo":"-256204778801521440"},"rq.p":{"bits":"80","hi":"538917354297457935731679","lo":"-538917354297457935731679"},"rq.q":{"bits":"56","hi":"32121977466193314","lo":"-32121977466193315"},"rq.t":{"bits":"63","hi":"2717371935163636773","lo":"-2717371935163636773"},"rq.y":{"bits":"56","hi":"32121977466193330","lo":"-32121977466193299"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"9"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"40","hi":"283323814454","lo":"-283323814454","policy":"check","result":{"bits":"56","hi":"32121977466193330","lo":"-32121977466193299"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"74","hi":"8191859483341710468646","lo":"0"},"igdn.gx2":{"bits":"89","hi":"291308480943618803505442964","lo":"0"},"igdn.r":{"bits":"38","hi":"90508891736","lo":"2931"},"igdn.term":{"bits":"73","hi":"4445014662835980278098","lo":"0"},"igdn.x2":{"bits":"78","hi":"80272383836764619318116","lo":"0"},"igdn.xr":{"bits":"76","hi":"25643324448647637952144","lo":"-25643324448647637952144"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"52","hi":"1611350810072462","lo":"-1611350810072462","policy":"check","result":{"bits":"64","hi":"6260577257970614734","lo":"-6260577257970614735"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"63","hi":"2357406235136011906","lo":"-2357406235136011906"},"convT.term":{"bits":"59","hi":"256204778801521458","lo":"-256204778801521458"},"rq.p":{"bits":"80","hi":"509275183788902924076992","lo":"-509275183788902924076992"},"rq.q":{"bits":"56","hi":"30355166422659332","lo":"-30355166422659333"},"rq.t":{"bits":"63","hi":"2357406235136011906","lo":"-2357406235136011906"},"rq.y":{"bits":"56","hi":"30355166422659330","lo":"-30355166422659335"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"9"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"56","hi":"30355166422659330","lo":"-30355166422659335","policy":"derived","result":{"bits":"56","hi":"30355166422659330","lo":"-30355166422659335"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"14","hi":"4096","lo":"0","policy":"derived","result":{"bits":"14","hi":"4096","lo":"0"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{"rq.p":{"bits":"21","hi":"1046528","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"14","hi":"4096","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"5"}],"saturated":false}],"scalars":[]}],"lowering":"whm1/1","set_sha256":"13e8b0d18e001eb9f0160309a02755b35a14f71ba0bcaa13f373e32b931ab818","verdict":{"acc32":false,"acc32_first_failure":{"bits":"53","graph":"h_s","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_hyper/7aceaa1aad145d6131a92804d5f6979e5971a4f12cd173dc6828befe2d397e8a.json b/wai/ops-conformance/certificates/wai.neural.int_hyper/7aceaa1aad145d6131a92804d5f6979e5971a4f12cd173dc6828befe2d397e8a.json new file mode 100644 index 000000000..1e5159ea7 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_hyper/7aceaa1aad145d6131a92804d5f6979e5971a4f12cd173dc6828befe2d397e8a.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_hyper","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"a907e0440876458a45cf0662560b1b057a55ca0728963529f1facd1c63c02292","inputs":[{"hi":"1725284705734151","kind":"data","lo":"-1725284705734151","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"h_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"conv.acc":{"bits":"64","hi":"5170678263085250547","lo":"-5170678263085250547"},"conv.term":{"bits":"60","hi":"512409557603042847","lo":"-512409557603042847"},"rq.p":{"bits":"76","hi":"18938734886820221661915","lo":"-18938734886820221661915"},"rq.q":{"bits":"64","hi":"4623714571977593179","lo":"-4623714571977593180"},"rq.t":{"bits":"64","hi":"5170678263085250547","lo":"-5170678263085250547"},"rq.y":{"bits":"64","hi":"4623714571977593632","lo":"-4623714571977592727"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"64","hi":"4623714571977593632","lo":"-4623714571977592727","policy":"derived","result":{"bits":"64","hi":"4623714571977593632","lo":"-4623714571977592727"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"51","hi":"868490775598378","lo":"0","policy":"check","result":{"bits":"64","hi":"4623714571977593632","lo":"0"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"62","hi":"1404349584142577226","lo":"-1560677923750285266"},"convT.term":{"bits":"59","hi":"256204778801521510","lo":"-250993834147931242"},"rq.p":{"bits":"73","hi":"3328308514417908025620","lo":"-3187576532158395657744"},"rq.q":{"bits":"61","hi":"812575320902809576","lo":"-778216926796483315"},"rq.t":{"bits":"62","hi":"1404349584142577226","lo":"-1560677923750285266"},"rq.y":{"bits":"61","hi":"812575320902808927","lo":"-778216926796484338"}},"k_c":"0","mac":{"a_bits":["51"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"61","hi":"812575320902808927","lo":"-778216926796484338","policy":"derived","result":{"bits":"61","hi":"812575320902808927","lo":"-778216926796484338"},"tensor":"3"}],"saturated":false}],"scalars":[]},{"graph_sha256":"d962c22698aae16dc6c8e7a5bd25a588caa4e81575256851e8fecea67a06f664","inputs":[{"hi":"1713744339809508","kind":"data","lo":"-1713744339809508","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"62","hi":"2130184214383218444","lo":"-2130184214383218444"},"convT.term":{"bits":"60","hi":"512409557603042892","lo":"-512409557603042892"},"rq.p":{"bits":"73","hi":"4576273205389562354688","lo":"-4576273205389562354688"},"rq.q":{"bits":"61","hi":"1117254200534561121","lo":"-1117254200534561122"},"rq.t":{"bits":"62","hi":"2130184214383218444","lo":"-2130184214383218444"},"rq.y":{"bits":"61","hi":"1117254200534561544","lo":"-1117254200534560699"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"37","hi":"37320054535","lo":"-37320054535","policy":"check","result":{"bits":"61","hi":"1117254200534561544","lo":"-1117254200534560699"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"73","hi":"2653639066344213714446","lo":"0"},"igdn.gx2":{"bits":"82","hi":"1366323527555961958966725","lo":"0"},"igdn.r":{"bits":"37","hi":"51513484315","lo":"198"},"igdn.term":{"bits":"72","hi":"1334300319878869100553","lo":"0"},"igdn.x2":{"bits":"72","hi":"1392786470495374066225","lo":"0"},"igdn.xr":{"bits":"72","hi":"1922486043923667118525","lo":"-1922486043923667118525"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"55","hi":"14081484025732482","lo":"-14081484025732482","policy":"check","result":{"bits":"64","hi":"7509711109076824681","lo":"-7509711109076824682"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"leaky.p":{"bits":"64","hi":"-655","lo":"-9223372036854775710"}},"npu_flags":[],"op":"leaky","out":[{"bits":"55","hi":"11386879057845402","lo":"-2251799813685248","policy":"check","result":{"bits":"55","hi":"14081484025732482","lo":"-2251799813685248"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{"conv.acc":{"bits":"64","hi":"3491757551090684724","lo":"-4676170893091885362"},"conv.term":{"bits":"63","hi":"2744237852940741882","lo":"-3074457345618258540"},"rq.p":{"bits":"75","hi":"10655004286560992135480","lo":"-10224198942285986174148"},"rq.q":{"bits":"63","hi":"2601319405898679720","lo":"-2496142319894039594"},"rq.t":{"bits":"64","hi":"3491757551090684724","lo":"-4676170893091885362"},"rq.y":{"bits":"63","hi":"2601319405898680095","lo":"-2496142319894039151"}},"k_c":"0","mac":{"a_bits":["55"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"63","hi":"2601319405898680095","lo":"-2496142319894039151","policy":"derived","result":{"bits":"63","hi":"2601319405898680095","lo":"-2496142319894039151"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"10","hi":"256","lo":"0","policy":"derived","result":{"bits":"10","hi":"256","lo":"0"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{"rq.p":{"bits":"17","hi":"65408","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"10","hi":"256","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"6"}],"saturated":false}],"scalars":[]}],"lowering":"whm1/1","set_sha256":"7aceaa1aad145d6131a92804d5f6979e5971a4f12cd173dc6828befe2d397e8a","verdict":{"acc32":false,"acc32_first_failure":{"bits":"52","graph":"h_s","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_hyper/f16fd09cd79b831d7d821e030c05e99e9fb5ea216574e699944ea4e55ac0a404.json b/wai/ops-conformance/certificates/wai.neural.int_hyper/f16fd09cd79b831d7d821e030c05e99e9fb5ea216574e699944ea4e55ac0a404.json new file mode 100644 index 000000000..f682dd134 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_hyper/f16fd09cd79b831d7d821e030c05e99e9fb5ea216574e699944ea4e55ac0a404.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_hyper","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"57833bd8c4036043adec6428b32601847f088aec89fd5cb68cc588b8bbc19854","inputs":[{"hi":"938708276019","kind":"data","lo":"-938708276019","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"h_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"59","hi":"225429853777686831","lo":"-225429853777686831"},"convT.term":{"bits":"52","hi":"1921535841010893","lo":"-1921535841010893"},"rq.p":{"bits":"72","hi":"1679990979497800375896","lo":"-1679990979497800375896"},"rq.q":{"bits":"48","hi":"100135265558826","lo":"-100135265558827"},"rq.t":{"bits":"59","hi":"225429853777686831","lo":"-225429853777686831"},"rq.y":{"bits":"48","hi":"100135265560731","lo":"-100135265556922"}},"k_c":"0","mac":{"a_bits":["41"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"48","hi":"100135265560731","lo":"-100135265556922","policy":"check","result":{"bits":"48","hi":"100135265560731","lo":"-100135265556922"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"leaky.p":{"bits":"57","hi":"-655","lo":"-65588598939783910"}},"npu_flags":[],"op":"leaky","out":[{"bits":"41","hi":"563224965611","lo":"-563224965611","policy":"check","result":{"bits":"48","hi":"100135265560731","lo":"-1000802596128"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"61","hi":"582355464792943226","lo":"-582355464792943226"},"convT.term":{"bits":"52","hi":"1152921504605717","lo":"-1152921504605717"},"rq.p":{"bits":"74","hi":"5261083649050897081260","lo":"-5261083649050897081260"},"rq.q":{"bits":"50","hi":"313585022035294","lo":"-313585022035295"},"rq.t":{"bits":"61","hi":"582355464792943226","lo":"-582355464792943226"},"rq.y":{"bits":"50","hi":"313585022036575","lo":"-313585022034014"}},"k_c":"0","mac":{"a_bits":["41"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"50","hi":"313585022036575","lo":"-313585022034014","policy":"check","result":{"bits":"50","hi":"313585022036575","lo":"-313585022034014"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{"leaky.p":{"bits":"59","hi":"-655","lo":"-205398189432279170"}},"npu_flags":[],"op":"leaky","out":[{"bits":"41","hi":"1043009195576","lo":"-1043009195576","policy":"check","result":{"bits":"50","hi":"313585022036575","lo":"-3134127646367"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{"conv.acc":{"bits":"60","hi":"569198279274103752","lo":"-569198279274103752"},"conv.term":{"bits":"52","hi":"2135039823344072","lo":"-2135039823344072"},"rq.p":{"bits":"76","hi":"36158509277380092942360","lo":"-36158509277380092942360"},"rq.q":{"bits":"52","hi":"2155215101085906","lo":"-2155215101085907"},"rq.t":{"bits":"60","hi":"569198279274103752","lo":"-569198279274103752"},"rq.y":{"bits":"52","hi":"2155215101090341","lo":"-2155215101081472"}},"k_c":"0","mac":{"a_bits":["41"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"52","hi":"2155215101090341","lo":"-2155215101081472","policy":"derived","result":{"bits":"52","hi":"2155215101090341","lo":"-2155215101081472"},"tensor":"5"}],"saturated":false}],"scalars":[]},{"graph_sha256":"b2fcecfef162a7baa4a21be6870e743bf33004ef71b72ec68b9cfde0c6677bdb","inputs":[{"hi":"563224965611","kind":"data","lo":"-563224965611","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"58","hi":"124948079271006684","lo":"-124948079271006684"},"convT.term":{"bits":"52","hi":"1152921504605717","lo":"-1152921504605717"},"rq.p":{"bits":"72","hi":"1293019994137330423734","lo":"-1293019994137330423734"},"rq.q":{"bits":"48","hi":"77069997438033","lo":"-77069997438034"},"rq.t":{"bits":"58","hi":"124948079271006684","lo":"-124948079271006684"},"rq.y":{"bits":"48","hi":"77069997437275","lo":"-77069997438792"}},"k_c":"0","mac":{"a_bits":["41"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"39","hi":"222158029149","lo":"-222158029149","policy":"check","result":{"bits":"48","hi":"77069997437275","lo":"-77069997438792"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"71","hi":"595690372055908745247","lo":"0"},"igdn.gx2":{"bits":"85","hi":"9870837983073586732840200","lo":"0"},"igdn.r":{"bits":"36","hi":"24406768980","lo":"4"},"igdn.term":{"bits":"69","hi":"150617034653832805371","lo":"0"},"igdn.x2":{"bits":"77","hi":"49354189915367933664201","lo":"0"},"igdn.xr":{"bits":"74","hi":"5422159694491748998020","lo":"-5422159694491748998020"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"41","hi":"938708276019","lo":"-938708276019","policy":"check","result":{"bits":"62","hi":"1323769456663024657","lo":"-1323769456663024658"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"60","hi":"336862035807350283","lo":"-336862035807350283"},"convT.term":{"bits":"52","hi":"1921535841010893","lo":"-1921535841010893"},"rq.p":{"bits":"73","hi":"2458876774503350596176","lo":"-2458876774503350596176"},"rq.q":{"bits":"49","hi":"146560476690730","lo":"-146560476690731"},"rq.t":{"bits":"60","hi":"336862035807350283","lo":"-336862035807350283"},"rq.y":{"bits":"49","hi":"146560476690748","lo":"-146560476690713"}},"k_c":"0","mac":{"a_bits":["41"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"91362748885","lo":"-91362748885","policy":"check","result":{"bits":"49","hi":"146560476690748","lo":"-146560476690713"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{"igdn.N":{"bits":"72","hi":"1688127915469323427149","lo":"0"},"igdn.gx2":{"bits":"87","hi":"58363285971694392652629200","lo":"0"},"igdn.r":{"bits":"37","hi":"41086833845","lo":"4"},"igdn.term":{"bits":"71","hi":"890553069636450083200","lo":"0"},"igdn.x2":{"bits":"74","hi":"8347151883823568743225","lo":"0"},"igdn.xr":{"bits":"73","hi":"3753806083060454012825","lo":"-3753806083060454012825"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"41","hi":"938708276019","lo":"-938708276019","policy":"check","result":{"bits":"61","hi":"916456563247181155","lo":"-916456563247181156"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{"convT.acc":{"bits":"60","hi":"442247059122899337","lo":"-442247059122899337"},"convT.term":{"bits":"52","hi":"1921535841010893","lo":"-1921535841010893"},"rq.p":{"bits":"72","hi":"2241157162608569296944","lo":"-2241157162608569296944"},"rq.q":{"bits":"48","hi":"133583376563106","lo":"-133583376563107"},"rq.t":{"bits":"60","hi":"442247059122899337","lo":"-442247059122899337"},"rq.y":{"bits":"48","hi":"133583376563077","lo":"-133583376563136"}},"k_c":"0","mac":{"a_bits":["41"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"36","hi":"32461896744","lo":"-32461896744","policy":"check","result":{"bits":"48","hi":"133583376563077","lo":"-133583376563136"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"5","intermediates":{"igdn.N":{"bits":"78","hi":"94186134156856156797757","lo":"0"},"igdn.gx2":{"bits":"90","hi":"462306785154791551300866240","lo":"0"},"igdn.r":{"bits":"40","hi":"306897595554","lo":"4"},"igdn.term":{"bits":"74","hi":"7054241716839470692457","lo":"0"},"igdn.x2":{"bits":"71","hi":"1053774740218117801536","lo":"0"},"igdn.xr":{"bits":"75","hi":"9962478057855821476176","lo":"-9962478057855821476176"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"41","hi":"938708276019","lo":"-938708276019","policy":"check","result":{"bits":"63","hi":"2432245619593706415","lo":"-2432245619593706416"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"6","intermediates":{"convT.acc":{"bits":"60","hi":"301042805411017281","lo":"-301042805411017281"},"convT.term":{"bits":"52","hi":"1921535841010893","lo":"-1921535841010893"},"rq.p":{"bits":"71","hi":"1168325338503655114533","lo":"-1168325338503655114533"},"rq.q":{"bits":"47","hi":"69637616783598","lo":"-69637616783599"},"rq.t":{"bits":"60","hi":"301042805411017281","lo":"-301042805411017281"},"rq.y":{"bits":"47","hi":"69637616783870","lo":"-69637616783327"}},"k_c":"0","mac":{"a_bits":["41"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"47","hi":"69637616783870","lo":"-69637616783327","policy":"derived","result":{"bits":"47","hi":"69637616783870","lo":"-69637616783327"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"7","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"14","hi":"4096","lo":"0","policy":"derived","result":{"bits":"14","hi":"4096","lo":"0"},"tensor":"8"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"8","intermediates":{"rq.p":{"bits":"21","hi":"1046528","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"14","hi":"4096","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"9"}],"saturated":false}],"scalars":[]}],"lowering":"whm1/1","set_sha256":"f16fd09cd79b831d7d821e030c05e99e9fb5ea216574e699944ea4e55ac0a404","verdict":{"acc32":false,"acc32_first_failure":{"bits":"41","graph":"h_s","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_mlicpp/07e1835da60333d5c5a586da7fc27f2db78b8ccd146b100c61362d4ce768fc1c.json b/wai/ops-conformance/certificates/wai.neural.int_mlicpp/07e1835da60333d5c5a586da7fc27f2db78b8ccd146b100c61362d4ce768fc1c.json new file mode 100644 index 000000000..6a13dbc8f --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_mlicpp/07e1835da60333d5c5a586da7fc27f2db78b8ccd146b100c61362d4ce768fc1c.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_mlicpp","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"b414de26d5a24c66f7e1e13c70a82cf17c161bc71a3e72247ccbb96b8229d156","inputs":[{"hi":"8147855156232134","kind":"data","lo":"-8147855156232134","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"h_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"62","hi":"2305843009213693922","lo":"-2305843009213693922"},"convT.term":{"bits":"62","hi":"2305843009213693922","lo":"-2305843009213693922"},"rq.p":{"bits":"73","hi":"2499533821987644211448","lo":"-2499533821987644211448"},"rq.q":{"bits":"61","hi":"610237749508702200","lo":"-610237749508702201"},"rq.t":{"bits":"62","hi":"2305843009213693922","lo":"-2305843009213693922"},"rq.y":{"bits":"61","hi":"610237749508701536","lo":"-610237749508702865"}},"k_c":"0","mac":{"a_bits":["54"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"61","hi":"610237749508701536","lo":"-610237749508702865","policy":"derived","result":{"bits":"61","hi":"610237749508701536","lo":"-610237749508702865"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"61","hi":"610237749508701536","lo":"0","policy":"derived","result":{"bits":"61","hi":"610237749508701536","lo":"0"},"tensor":"2"}],"saturated":false}],"scalars":[]},{"graph_sha256":"ebfe2dfb653455a306bbbd6ab8de5f8a90c900b7ddbe96e8d15ef0175d3dd1dd","inputs":[{"hi":"577037790093517","kind":"data","lo":"-577037790093517","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"entropy","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"conv.acc":{"bits":"64","hi":"5145445974263891089","lo":"-5145445974263891089"},"conv.term":{"bits":"59","hi":"170803185867681032","lo":"-170803185867681032"},"rq.p":{"bits":"75","hi":"11939933810961122348607","lo":"-11939933810961122348607"},"rq.q":{"bits":"63","hi":"2915022903066680260","lo":"-2915022903066680261"},"rq.t":{"bits":"64","hi":"5145445974263891089","lo":"-5145445974263891089"},"rq.y":{"bits":"63","hi":"2915022903066679315","lo":"-2915022903066681206"}},"k_c":"0","mac":{"a_bits":["51"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"51","hi":"703698179358722","lo":"-703698179358722","policy":"check","result":{"bits":"63","hi":"2915022903066679315","lo":"-2915022903066681206"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"leaky.p":{"bits":"64","hi":"9223372036854769254","lo":"13107"}},"npu_flags":[],"op":"leaky","out":[{"bits":"51","hi":"703698179358722","lo":"0","policy":"derived","result":{"bits":"51","hi":"703698179358722","lo":"0"},"tensor":"2"}],"saturated":false}],"scalars":[]},{"graph_sha256":"5fe266f41ec77433d87f3c9b22efdb5aff775ed7ff62f13f3f11b55eb9780aa4","inputs":[{"hi":"1719495159741755","kind":"data","lo":"-1719495159741755","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"62","hi":"2171722386753836565","lo":"-2171722386753836565"},"convT.term":{"bits":"60","hi":"512409557603042990","lo":"-512409557603042990"},"rq.p":{"bits":"74","hi":"5935317282998235332145","lo":"-5935317282998235332145"},"rq.q":{"bits":"62","hi":"1449052071044491047","lo":"-1449052071044491048"},"rq.t":{"bits":"62","hi":"2171722386753836565","lo":"-2171722386753836565"},"rq.y":{"bits":"62","hi":"1449052071044491153","lo":"-1449052071044490942"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"37","hi":"37561683460","lo":"-37561683460","policy":"check","result":{"bits":"62","hi":"1449052071044491153","lo":"-1449052071044490942"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"73","hi":"2726691061862442560876","lo":"0"},"igdn.gx2":{"bits":"82","hi":"1348801341517871118449600","lo":"0"},"igdn.r":{"bits":"37","hi":"52217727467","lo":"165"},"igdn.term":{"bits":"72","hi":"1317188810076046014110","lo":"0"},"igdn.x2":{"bits":"72","hi":"1410880064349237571600","lo":"0"},"igdn.xr":{"bits":"72","hi":"1961385750116001595820","lo":"-1961385750116001595820"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"64","hi":"7661663086390631233","lo":"-7661663086390631234","policy":"derived","result":{"bits":"64","hi":"7661663086390631233","lo":"-7661663086390631234"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"10","hi":"256","lo":"0","policy":"derived","result":{"bits":"10","hi":"256","lo":"0"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{"rq.p":{"bits":"17","hi":"65408","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"10","hi":"256","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"4"}],"saturated":false}],"scalars":[]}],"lowering":"wmb1/1","set_sha256":"07e1835da60333d5c5a586da7fc27f2db78b8ccd146b100c61362d4ce768fc1c","verdict":{"acc32":false,"acc32_first_failure":{"bits":"54","graph":"h_s","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_mlicpp/7ef44f3b1fc4a2df6c3e3b68460f595cae3d31cb7f9018699e29e738340272a4.json b/wai/ops-conformance/certificates/wai.neural.int_mlicpp/7ef44f3b1fc4a2df6c3e3b68460f595cae3d31cb7f9018699e29e738340272a4.json new file mode 100644 index 000000000..00d696bb9 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_mlicpp/7ef44f3b1fc4a2df6c3e3b68460f595cae3d31cb7f9018699e29e738340272a4.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_mlicpp","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"02792c6954393fa05f413212ae22edfdce81394d3ebff250a37ef1f8eccff55e","inputs":[{"hi":"45057997248924","kind":"data","lo":"-45057997248924","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"h_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"62","hi":"1916226507002239872","lo":"-1916226507002239872"},"convT.term":{"bits":"58","hi":"92233720368547428","lo":"-92233720368547428"},"rq.p":{"bits":"73","hi":"3075543543738594994560","lo":"-3075543543738594994560"},"rq.q":{"bits":"49","hi":"183316680415785","lo":"-183316680415786"},"rq.t":{"bits":"62","hi":"1916226507002239872","lo":"-1916226507002239872"},"rq.y":{"bits":"49","hi":"183316680415681","lo":"-183316680415890"}},"k_c":"0","mac":{"a_bits":["47"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"49","hi":"183316680415681","lo":"-183316680415890","policy":"derived","result":{"bits":"49","hi":"183316680415681","lo":"-183316680415890"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"46","hi":"22528998624462","lo":"0","policy":"check","result":{"bits":"49","hi":"183316680415681","lo":"0"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"61","hi":"1020721340678499834","lo":"-1115793714873729474"},"convT.term":{"bits":"57","hi":"46116860184273714","lo":"-46116860184273714"},"rq.p":{"bits":"72","hi":"1170767377758239309598","lo":"-1276468009815546518256"},"rq.q":{"bits":"48","hi":"69783173665895","lo":"-76083422292206"},"rq.t":{"bits":"61","hi":"1020721340678499834","lo":"-1115793714873729474"},"rq.y":{"bits":"48","hi":"69783173665724","lo":"-76083422292240"}},"k_c":"0","mac":{"a_bits":["46"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"48","hi":"69783173665724","lo":"-76083422292240","policy":"derived","result":{"bits":"48","hi":"69783173665724","lo":"-76083422292240"},"tensor":"3"}],"saturated":false}],"scalars":[]},{"graph_sha256":"0757e26ba88fedefe1e88ea08cf0b6e2dd53c84b651b4b6bd9d6b3686a901314","inputs":[{"hi":"7509666208154","kind":"data","lo":"-7509666208154","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"entropy","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"conv.acc":{"bits":"64","hi":"4693398696438295074","lo":"-4693398696438295074"},"conv.term":{"bits":"55","hi":"15372286728091238","lo":"-15372286728091238"},"rq.p":{"bits":"73","hi":"2975614773541879076916","lo":"-2975614773541879076916"},"rq.q":{"bits":"49","hi":"177360461565368","lo":"-177360461565369"},"rq.t":{"bits":"64","hi":"4693398696438295074","lo":"-4693398696438295074"},"rq.y":{"bits":"49","hi":"177360461565252","lo":"-177360461565485"}},"k_c":"0","mac":{"a_bits":["44"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"49","hi":"177360461565252","lo":"-177360461565485","policy":"check","result":{"bits":"49","hi":"177360461565252","lo":"-177360461565485"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"leaky.p":{"bits":"58","hi":"-655","lo":"-116171102325392675"}},"npu_flags":[],"op":"leaky","out":[{"bits":"49","hi":"177360461565252","lo":"-1772630345542","policy":"check","result":{"bits":"49","hi":"177360461565252","lo":"-1772630345542"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"conv.acc":{"bits":"63","hi":"2693073932462816518","lo":"-2751382144940963184"},"conv.term":{"bits":"60","hi":"363056864824070844","lo":"-363056864824070844"},"rq.p":{"bits":"74","hi":"5703930588956245385124","lo":"-5808167707970373281424"},"rq.q":{"bits":"50","hi":"339980756578221","lo":"-346193773029469"},"rq.t":{"bits":"63","hi":"2693073932462816518","lo":"-2751382144940963184"},"rq.y":{"bits":"50","hi":"339980756619279","lo":"-346193773029369"}},"k_c":"0","mac":{"a_bits":["49"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"50","hi":"339980756619279","lo":"-346193773029369","policy":"derived","result":{"bits":"50","hi":"339980756619279","lo":"-346193773029369"},"tensor":"3"}],"saturated":false}],"scalars":[]},{"graph_sha256":"873760630947209dcaf216323954ec358f742df915acb7d645aa5f59d0c611fa","inputs":[{"hi":"22528998624462","kind":"data","lo":"-22528998624462","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"62","hi":"1819058935934935266","lo":"-1819058935934935266"},"convT.term":{"bits":"57","hi":"46116860184273714","lo":"-46116860184273714"},"rq.p":{"bits":"72","hi":"1826335171678675007064","lo":"-1826335171678675007064"},"rq.q":{"bits":"48","hi":"108858059148709","lo":"-108858059148710"},"rq.t":{"bits":"62","hi":"1819058935934935266","lo":"-1819058935934935266"},"rq.y":{"bits":"48","hi":"108858059148717","lo":"-108858059148702"}},"k_c":"0","mac":{"a_bits":["46"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"39","hi":"196507649010","lo":"-196507649010","policy":"check","result":{"bits":"48","hi":"108858059148717","lo":"-108858059148702"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"74","hi":"7868471225265009676159","lo":"0"},"igdn.gx2":{"bits":"89","hi":"302782223232508292557964100","lo":"0"},"igdn.r":{"bits":"38","hi":"88704403640","lo":"4131"},"igdn.term":{"bits":"73","hi":"4620090076179630928924","lo":"0"},"igdn.x2":{"bits":"77","hi":"38615256119437353980100","lo":"0"},"igdn.xr":{"bits":"75","hi":"17431093816130486396400","lo":"-17431093816130486396400"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"46","hi":"22528998624462","lo":"-22528998624462","policy":"check","result":{"bits":"63","hi":"4255638138703732030","lo":"-4255638138703732031"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"62","hi":"1892345768460310152","lo":"-1892345768460310152"},"convT.term":{"bits":"57","hi":"46116860184273714","lo":"-46116860184273714"},"rq.p":{"bits":"72","hi":"1879099348081087980936","lo":"-1879099348081087980936"},"rq.q":{"bits":"48","hi":"112003049140041","lo":"-112003049140042"},"rq.t":{"bits":"62","hi":"1892345768460310152","lo":"-1892345768460310152"},"rq.y":{"bits":"48","hi":"112003049140021","lo":"-112003049140062"}},"k_c":"0","mac":{"a_bits":["46"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"39","hi":"196413780387","lo":"-196413780387","policy":"check","result":{"bits":"48","hi":"112003049140021","lo":"-112003049140062"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{"igdn.N":{"bits":"74","hi":"8133504966441901325974","lo":"0"},"igdn.gx2":{"bits":"89","hi":"303071699277169903072905264","lo":"0"},"igdn.r":{"bits":"38","hi":"90185946612","lo":"4152"},"igdn.term":{"bits":"73","hi":"4624507130083769272963","lo":"0"},"igdn.x2":{"bits":"77","hi":"38578373125912665869769","lo":"0"},"igdn.xr":{"bits":"75","hi":"17713762711843074698844","lo":"-17713762711843074698844"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"46","hi":"22528998624462","lo":"-22528998624462","policy":"check","result":{"bits":"63","hi":"4324649099571063158","lo":"-4324649099571063159"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{"convT.acc":{"bits":"62","hi":"1972143481588154556","lo":"-1972143481588154556"},"convT.term":{"bits":"57","hi":"46116860184273714","lo":"-46116860184273714"},"rq.p":{"bits":"69","hi":"234685074308990392164","lo":"-234685074308990392164"},"rq.q":{"bits":"45","hi":"13988320488273","lo":"-13988320488274"},"rq.t":{"bits":"62","hi":"1972143481588154556","lo":"-1972143481588154556"},"rq.y":{"bits":"45","hi":"13988320490416","lo":"-13988320486131"}},"k_c":"0","mac":{"a_bits":["46"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"45","hi":"13988320490416","lo":"-13988320486131","policy":"derived","result":{"bits":"45","hi":"13988320490416","lo":"-13988320486131"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"14","hi":"4096","lo":"0","policy":"derived","result":{"bits":"14","hi":"4096","lo":"0"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"6","intermediates":{"rq.p":{"bits":"21","hi":"1046528","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"14","hi":"4096","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"7"}],"saturated":false}],"scalars":[]}],"lowering":"wmb1/1","set_sha256":"7ef44f3b1fc4a2df6c3e3b68460f595cae3d31cb7f9018699e29e738340272a4","verdict":{"acc32":false,"acc32_first_failure":{"bits":"47","graph":"h_s","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_synth/00c2274be6b49039365a16a357f41162095db65ed4166a4c70f5ddb97e16b4d1.json b/wai/ops-conformance/certificates/wai.neural.int_synth/00c2274be6b49039365a16a357f41162095db65ed4166a4c70f5ddb97e16b4d1.json new file mode 100644 index 000000000..0cdd707d3 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_synth/00c2274be6b49039365a16a357f41162095db65ed4166a4c70f5ddb97e16b4d1.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_synth","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"e965a537999df89fd1d9aa3ca5a554a814d7c0aebc31d432af619355fa1d7d97","inputs":[{"hi":"127","kind":"data","lo":"-128","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"synth","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"16","hi":"20902","lo":"-20730"},"convT.term":{"bits":"14","hi":"5120","lo":"-5120"},"rq.p":{"bits":"16","hi":"20902","lo":"-20730"},"rq.q":{"bits":"13","hi":"2612","lo":"-2592"},"rq.t":{"bits":"16","hi":"20902","lo":"-20730"},"rq.y":{"bits":"13","hi":"2612","lo":"-2592"}},"k_c":"419430","mac":{"a_bits":["8"],"w_bits":"7"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"13","hi":"2612","lo":"-2592","policy":"derived","result":{"bits":"13","hi":"2612","lo":"-2592"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"13","hi":"2612","lo":"0","policy":"derived","result":{"bits":"13","hi":"2612","lo":"0"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"21","hi":"762704","lo":"-877680"},"convT.term":{"bits":"18","hi":"104480","lo":"-104480"},"rq.p":{"bits":"21","hi":"762704","lo":"-877680"},"rq.q":{"bits":"17","hi":"47669","lo":"-54855"},"rq.t":{"bits":"21","hi":"762704","lo":"-877680"},"rq.y":{"bits":"17","hi":"47669","lo":"-54855"}},"k_c":"20554","mac":{"a_bits":["13"],"w_bits":"7"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"17","hi":"47669","lo":"-54855","policy":"derived","result":{"bits":"17","hi":"47669","lo":"-54855"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"4"}],"saturated":false}],"scalars":[]}],"lowering":"int_synth/1","set_sha256":"00c2274be6b49039365a16a357f41162095db65ed4166a4c70f5ddb97e16b4d1","verdict":{"acc32":true,"acc64":true,"npu":true,"npu_flags":[],"npu_reasons":[]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_synth/1c4705d17c01f865b20d785191c7f63b5c18dcc8fce77e15852cf8240b7368be.json b/wai/ops-conformance/certificates/wai.neural.int_synth/1c4705d17c01f865b20d785191c7f63b5c18dcc8fce77e15852cf8240b7368be.json new file mode 100644 index 000000000..aec3aace7 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_synth/1c4705d17c01f865b20d785191c7f63b5c18dcc8fce77e15852cf8240b7368be.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_synth","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"04147b8ba5e5544c15466d9bfc66a813e6abdc58bd67314c7cbbb6cd38e9e324","inputs":[{"hi":"127","kind":"data","lo":"-128","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"synth","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"16","hi":"22516","lo":"-22539"},"convT.term":{"bits":"13","hi":"2304","lo":"-2286"},"rq.p":{"bits":"16","hi":"22516","lo":"-22539"},"rq.q":{"bits":"12","hi":"1407","lo":"-1409"},"rq.t":{"bits":"16","hi":"22516","lo":"-22539"},"rq.y":{"bits":"12","hi":"1407","lo":"-1409"}},"k_c":"932067","mac":{"a_bits":["8"],"w_bits":"6"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"12","hi":"1407","lo":"-1409","policy":"derived","result":{"bits":"12","hi":"1407","lo":"-1409"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"12","hi":"1407","lo":"0","policy":"derived","result":{"bits":"12","hi":"1407","lo":"0"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"20","hi":"40803","lo":"-304023"},"convT.term":{"bits":"16","hi":"8442","lo":"-25326"},"rq.p":{"bits":"20","hi":"40803","lo":"-304023"},"rq.q":{"bits":"15","hi":"1275","lo":"-9501"},"rq.t":{"bits":"20","hi":"40803","lo":"-304023"},"rq.y":{"bits":"15","hi":"1275","lo":"-9501"}},"k_c":"84793","mac":{"a_bits":["12"],"w_bits":"6"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"15","hi":"1275","lo":"-9501","policy":"derived","result":{"bits":"15","hi":"1275","lo":"-9501"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"4"}],"saturated":false}],"scalars":[]}],"lowering":"int_synth/1","set_sha256":"1c4705d17c01f865b20d785191c7f63b5c18dcc8fce77e15852cf8240b7368be","verdict":{"acc32":true,"acc64":true,"npu":true,"npu_flags":[],"npu_reasons":[]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_synth/21f092964e1319eca7e494ba3f6794e3166886d50e9dd74d00935c5b317055a9.json b/wai/ops-conformance/certificates/wai.neural.int_synth/21f092964e1319eca7e494ba3f6794e3166886d50e9dd74d00935c5b317055a9.json new file mode 100644 index 000000000..2453083dc --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_synth/21f092964e1319eca7e494ba3f6794e3166886d50e9dd74d00935c5b317055a9.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_synth","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"0be18812f9593d58117b14b6882e6fa4038b2af4cd85e586292292dddf224ebd","inputs":[{"hi":"127","kind":"data","lo":"-128","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"synth","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"17","hi":"35947","lo":"-35878"},"convT.term":{"bits":"13","hi":"2304","lo":"-2286"},"rq.p":{"bits":"17","hi":"35947","lo":"-35878"},"rq.q":{"bits":"11","hi":"561","lo":"-561"},"rq.t":{"bits":"17","hi":"35947","lo":"-35878"},"rq.y":{"bits":"11","hi":"561","lo":"-561"}},"k_c":"932067","mac":{"a_bits":["8"],"w_bits":"6"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"11","hi":"561","lo":"-561","policy":"derived","result":{"bits":"11","hi":"561","lo":"-561"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"2"}],"saturated":false}],"scalars":[]}],"lowering":"int_synth/1","set_sha256":"21f092964e1319eca7e494ba3f6794e3166886d50e9dd74d00935c5b317055a9","verdict":{"acc32":true,"acc64":true,"npu":true,"npu_flags":[],"npu_reasons":[]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_synth/50868e72f5f1599569c413ed1f67ab8610fa0b3c17919162cbf370f49275125c.json b/wai/ops-conformance/certificates/wai.neural.int_synth/50868e72f5f1599569c413ed1f67ab8610fa0b3c17919162cbf370f49275125c.json new file mode 100644 index 000000000..2603a2bc0 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_synth/50868e72f5f1599569c413ed1f67ab8610fa0b3c17919162cbf370f49275125c.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_synth","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"0424c3e9fc68733885cd528542317494c1debba38ce507b31d23590fcc70b102","inputs":[{"hi":"127","kind":"data","lo":"-128","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"synth","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"22","hi":"1486634","lo":"-1485967"},"convT.term":{"bits":"15","hi":"16256","lo":"-16129"},"rq.p":{"bits":"22","hi":"1486634","lo":"-1485967"},"rq.q":{"bits":"13","hi":"2903","lo":"-2903"},"rq.t":{"bits":"22","hi":"1486634","lo":"-1485967"},"rq.y":{"bits":"13","hi":"2903","lo":"-2903"}},"k_c":"132104","mac":{"a_bits":["8"],"w_bits":"8"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"13","hi":"2903","lo":"-2903","policy":"derived","result":{"bits":"13","hi":"2903","lo":"-2903"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"13","hi":"2903","lo":"0","policy":"derived","result":{"bits":"13","hi":"2903","lo":"0"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"25","hi":"6369182","lo":"-16550003"},"convT.term":{"bits":"20","hi":"223531","lo":"-368681"},"rq.p":{"bits":"25","hi":"6369182","lo":"-16550003"},"rq.q":{"bits":"20","hi":"199036","lo":"-517188"},"rq.t":{"bits":"25","hi":"6369182","lo":"-16550003"},"rq.y":{"bits":"20","hi":"199036","lo":"-517188"}},"k_c":"5824","mac":{"a_bits":["13"],"w_bits":"8"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"20","hi":"199036","lo":"-517188","policy":"derived","result":{"bits":"20","hi":"199036","lo":"-517188"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"19","hi":"199036","lo":"0","policy":"derived","result":{"bits":"19","hi":"199036","lo":"0"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{"convT.acc":{"bits":"30","hi":"189482281","lo":"-488832473"},"convT.term":{"bits":"26","hi":"6369152","lo":"-25277572"},"rq.p":{"bits":"30","hi":"189482281","lo":"-488832473"},"rq.q":{"bits":"26","hi":"11842642","lo":"-30552030"},"rq.t":{"bits":"30","hi":"189482281","lo":"-488832473"},"rq.y":{"bits":"26","hi":"11842642","lo":"-30552030"}},"k_c":"84","mac":{"a_bits":["19"],"w_bits":"8"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"26","hi":"11842642","lo":"-30552030","policy":"derived","result":{"bits":"26","hi":"11842642","lo":"-30552030"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"25","hi":"11842642","lo":"0","policy":"derived","result":{"bits":"25","hi":"11842642","lo":"0"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"6","intermediates":{"convT.acc":{"bits":"36","hi":"26172239136","lo":"-25165614250"},"convT.term":{"bits":"32","hi":"1373746472","lo":"-1504015534"},"rq.p":{"bits":"36","hi":"26172239136","lo":"-25165614250"},"rq.q":{"bits":"32","hi":"1635764946","lo":"-1572850891"},"rq.t":{"bits":"36","hi":"26172239136","lo":"-25165614250"},"rq.y":{"bits":"32","hi":"1635764946","lo":"-1572850891"}},"k_c":"1","mac":{"a_bits":["25"],"w_bits":"8"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"32","hi":"1635764946","lo":"-1572850891","policy":"derived","result":{"bits":"32","hi":"1635764946","lo":"-1572850891"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"7","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"8"}],"saturated":false}],"scalars":[]}],"lowering":"int_synth/1","set_sha256":"50868e72f5f1599569c413ed1f67ab8610fa0b3c17919162cbf370f49275125c","verdict":{"acc32":false,"acc32_first_failure":{"bits":"36","graph":"synth","index":"6","key":"convT.acc","where":"node"},"acc64":true,"npu":false,"npu_flags":[],"npu_reasons":["acc32"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_synth/76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac.json b/wai/ops-conformance/certificates/wai.neural.int_synth/76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac.json new file mode 100644 index 000000000..326c9bbbe --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_synth/76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_synth","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"633c99de690fc890904ad9a73f3324eef8a197d7f98e6e9b6b37dc1d9f48f8d1","inputs":[{"hi":"127","kind":"data","lo":"-128","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"synth","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"10","hi":"256","lo":"-128"},"convT.term":{"bits":"8","hi":"127","lo":"-128"},"rq.p":{"bits":"10","hi":"256","lo":"-128"},"rq.q":{"bits":"2","hi":"1","lo":"-1"},"rq.t":{"bits":"10","hi":"256","lo":"-128"},"rq.y":{"bits":"2","hi":"1","lo":"-1"}},"k_c":"16777215","mac":{"a_bits":["8"],"w_bits":"2"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"2","hi":"1","lo":"-1","policy":"derived","result":{"bits":"2","hi":"1","lo":"-1"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"convT.acc":{"bits":"33","hi":"2147483648","lo":"-2147483648"},"convT.term":{"bits":"32","hi":"1073741824","lo":"-1073741824"},"rq.p":{"bits":"33","hi":"2147483648","lo":"-2147483648"},"rq.q":{"bits":"33","hi":"2147483648","lo":"-2147483648"},"rq.t":{"bits":"33","hi":"2147483648","lo":"-2147483648"},"rq.y":{"bits":"33","hi":"2147483648","lo":"-2147483648"}},"k_c":"1","mac":{"a_bits":["2"],"w_bits":"32"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"33","hi":"2147483648","lo":"-2147483648","policy":"derived","result":{"bits":"33","hi":"2147483648","lo":"-2147483648"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"3"}],"saturated":false}],"scalars":[]}],"lowering":"int_synth/1","set_sha256":"76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac","verdict":{"acc32":false,"acc32_first_failure":{"bits":"33","graph":"synth","index":"1","key":"convT.acc","where":"node"},"acc64":true,"npu":false,"npu_flags":[],"npu_reasons":["acc32"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_synth/76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac/synth.whg1 b/wai/ops-conformance/certificates/wai.neural.int_synth/76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac/synth.whg1 new file mode 100644 index 000000000..8c98c16c0 Binary files /dev/null and b/wai/ops-conformance/certificates/wai.neural.int_synth/76916c8f85da7663c09fba8cb091d628ed38328b680563285b8056cec82fd1ac/synth.whg1 differ diff --git a/wai/ops-conformance/certificates/wai.neural.int_synth/b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a.json b/wai/ops-conformance/certificates/wai.neural.int_synth/b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a.json new file mode 100644 index 000000000..3e6678c22 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_synth/b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_synth","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"98d845410a6af26ba1fbaa4b4c8b9cf1416e3036442fc8cc1f8499f765a4d0ea","inputs":[{"hi":"127","kind":"data","lo":"-128","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"synth","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"37","hi":"42128471623","lo":"-42460191872"},"convT.term":{"bits":"37","hi":"42128471623","lo":"-42460191872"},"rq.p":{"bits":"37","hi":"42128471623","lo":"-42460191872"},"rq.q":{"bits":"37","hi":"42128471623","lo":"-42460191872"},"rq.t":{"bits":"37","hi":"42128471623","lo":"-42460191872"},"rq.y":{"bits":"37","hi":"42128471623","lo":"-42460191872"}},"k_c":"0","mac":{"a_bits":["8"],"w_bits":"30"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"37","hi":"42128471623","lo":"-42460191872","policy":"derived","result":{"bits":"37","hi":"42128471623","lo":"-42460191872"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"37","hi":"42128471623","lo":"0","policy":"derived","result":{"bits":"37","hi":"42128471623","lo":"0"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":[],"index":"2","intermediates":{"convT.acc":{"bits":"65","hi":"9223372036854775808","lo":"0"},"convT.term":{"bits":"64","hi":"9223372036854775807","lo":"0"},"rq.p":{"bits":"65","hi":"9223372036854775808","lo":"0"},"rq.q":{"bits":"65","hi":"9223372036854775808","lo":"0"},"rq.t":{"bits":"65","hi":"9223372036854775808","lo":"0"},"rq.y":{"bits":"65","hi":"9223372036854775808","lo":"0"}},"k_c":"0","mac":{"a_bits":["37"],"w_bits":"29"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"65","hi":"9223372036854775808","lo":"0","policy":"derived","result":{"bits":"65","hi":"9223372036854775808","lo":"0"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"4"}],"saturated":false}],"scalars":[]}],"lowering":"int_synth/1","set_sha256":"b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a","verdict":{"acc32":false,"acc32_first_failure":{"bits":"37","graph":"synth","index":"0","key":"convT.acc","where":"node"},"acc64":false,"acc64_first_failure":{"bits":"65","graph":"synth","index":"2","key":"convT.acc","where":"node"},"npu":false,"npu_flags":[],"npu_reasons":["acc32"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.neural.int_synth/b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a/synth.whg1 b/wai/ops-conformance/certificates/wai.neural.int_synth/b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a/synth.whg1 new file mode 100644 index 000000000..6e029c42c Binary files /dev/null and b/wai/ops-conformance/certificates/wai.neural.int_synth/b35460f39f31a559e97e66b8dde4597a309cbc44199c40097f935dd8e6e7305a/synth.whg1 differ diff --git a/wai/ops-conformance/certificates/wai.neural.int_synth/c6a362696d61605931ef4da98ae630362dcd73ea6be7864db6e61d6c5abbcd24.json b/wai/ops-conformance/certificates/wai.neural.int_synth/c6a362696d61605931ef4da98ae630362dcd73ea6be7864db6e61d6c5abbcd24.json new file mode 100644 index 000000000..91d2b7340 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.neural.int_synth/c6a362696d61605931ef4da98ae630362dcd73ea6be7864db6e61d6c5abbcd24.json @@ -0,0 +1 @@ +{"capability":"wai.neural.int_synth","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"293aee268c980f56cb13fd77816693aa8fdef0e3c5fc4955a4f81e433a02e105","inputs":[{"hi":"127","kind":"data","lo":"-128","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"synth","nodes":[{"acc32_params":[],"fits":["acc32","acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"16","hi":"16895","lo":"-16956"},"convT.term":{"bits":"13","hi":"2304","lo":"-2286"},"rq.p":{"bits":"16","hi":"16895","lo":"-16956"},"rq.q":{"bits":"12","hi":"1055","lo":"-1060"},"rq.t":{"bits":"16","hi":"16895","lo":"-16956"},"rq.y":{"bits":"12","hi":"1055","lo":"-1060"}},"k_c":"932067","mac":{"a_bits":["8"],"w_bits":"6"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"12","hi":"1055","lo":"-1060","policy":"derived","result":{"bits":"12","hi":"1055","lo":"-1060"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"12","hi":"1055","lo":"0","policy":"derived","result":{"bits":"12","hi":"1055","lo":"0"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"20","hi":"41145","lo":"-310318"},"convT.term":{"bits":"16","hi":"6330","lo":"-18990"},"rq.p":{"bits":"20","hi":"41145","lo":"-310318"},"rq.q":{"bits":"15","hi":"1285","lo":"-9698"},"rq.t":{"bits":"20","hi":"41145","lo":"-310318"},"rq.y":{"bits":"15","hi":"1285","lo":"-9698"}},"k_c":"113084","mac":{"a_bits":["12"],"w_bits":"6"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"15","hi":"1285","lo":"-9698","policy":"derived","result":{"bits":"15","hi":"1285","lo":"-9698"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"relu","out":[{"bits":"12","hi":"1285","lo":"0","policy":"derived","result":{"bits":"12","hi":"1285","lo":"0"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{"convT.acc":{"bits":"20","hi":"51400","lo":"-514100"},"convT.term":{"bits":"16","hi":"7710","lo":"-23130"},"rq.p":{"bits":"20","hi":"51400","lo":"-514100"},"rq.q":{"bits":"16","hi":"3212","lo":"-32132"},"rq.t":{"bits":"20","hi":"51400","lo":"-514100"},"rq.y":{"bits":"16","hi":"3212","lo":"-32132"}},"k_c":"92844","mac":{"a_bits":["12"],"w_bits":"6"},"npu_flags":[],"op":"conv_transpose","out":[{"bits":"16","hi":"3212","lo":"-32132","policy":"derived","result":{"bits":"16","hi":"3212","lo":"-32132"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"6"}],"saturated":false}],"scalars":[]}],"lowering":"int_synth/1","set_sha256":"c6a362696d61605931ef4da98ae630362dcd73ea6be7864db6e61d6c5abbcd24","verdict":{"acc32":true,"acc64":true,"npu":true,"npu_flags":[],"npu_reasons":[]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.splat.int_codec/033a37c9d29d7ea9675a0b4a3e269d74f2ab874b5a3b1425eec69bf3bad8b26f.json b/wai/ops-conformance/certificates/wai.splat.int_codec/033a37c9d29d7ea9675a0b4a3e269d74f2ab874b5a3b1425eec69bf3bad8b26f.json new file mode 100644 index 000000000..c358ed090 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.splat.int_codec/033a37c9d29d7ea9675a0b4a3e269d74f2ab874b5a3b1425eec69bf3bad8b26f.json @@ -0,0 +1 @@ +{"capability":"wai.splat.int_codec","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"7082d056e453e9f814e0a7a62b317815364e911c358abbae96ef6d7dc648f070","inputs":[{"hi":"5632249656115","kind":"data","lo":"-5632249656115","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"61","hi":"884032273774154285","lo":"-884032273774154285"},"convT.term":{"bits":"55","hi":"11529215046067405","lo":"-11529215046067405"},"rq.p":{"bits":"70","hi":"305677959136398172000","lo":"-305677959136398172000"},"rq.q":{"bits":"46","hi":"18219826169991","lo":"-18219826169992"},"rq.t":{"bits":"61","hi":"884032273774154285","lo":"-884032273774154285"},"rq.y":{"bits":"46","hi":"18219826170500","lo":"-18219826169483"}},"k_c":"0","mac":{"a_bits":["44"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"89166253876","lo":"-89166253876","policy":"check","result":{"bits":"46","hi":"18219826170500","lo":"-18219826169483"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"79","hi":"164859282006515137208244","lo":"0"},"igdn.gx2":{"bits":"90","hi":"367644657812944418765929616","lo":"0"},"igdn.r":{"bits":"40","hi":"406028671409","lo":"4470"},"igdn.term":{"bits":"74","hi":"5609812283522711467985","lo":"0"},"igdn.x2":{"bits":"74","hi":"7950620830279285023376","lo":"0"},"igdn.xr":{"bits":"76","hi":"36204055595789876631284","lo":"-36204055595789876631284"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"44","hi":"5632249656115","lo":"-5632249656115","policy":"check","result":{"bits":"64","hi":"8838880760690887849","lo":"-8838880760690887850"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"61","hi":"805805958300373050","lo":"-805805958300373050"},"convT.term":{"bits":"55","hi":"11529215046067405","lo":"-11529215046067405"},"rq.p":{"bits":"70","hi":"404028584243961107750","lo":"-404028584243961107750"},"rq.q":{"bits":"46","hi":"24081980242965","lo":"-24081980242966"},"rq.t":{"bits":"61","hi":"805805958300373050","lo":"-805805958300373050"},"rq.y":{"bits":"46","hi":"24081980243505","lo":"-24081980242426"}},"k_c":"0","mac":{"a_bits":["44"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"46","hi":"24081980243505","lo":"-24081980242426","policy":"derived","result":{"bits":"46","hi":"24081980243505","lo":"-24081980242426"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"14","hi":"4096","lo":"0","policy":"derived","result":{"bits":"14","hi":"4096","lo":"0"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{"rq.p":{"bits":"21","hi":"1046528","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"14","hi":"4096","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"5"}],"saturated":false}],"scalars":[]}],"lowering":"whm1/1","set_sha256":"033a37c9d29d7ea9675a0b4a3e269d74f2ab874b5a3b1425eec69bf3bad8b26f","verdict":{"acc32":false,"acc32_first_failure":{"bits":"44","graph":"g_s","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.video.int_hyper/13e8b0d18e001eb9f0160309a02755b35a14f71ba0bcaa13f373e32b931ab818.json b/wai/ops-conformance/certificates/wai.video.int_hyper/13e8b0d18e001eb9f0160309a02755b35a14f71ba0bcaa13f373e32b931ab818.json new file mode 100644 index 000000000..9db73138e --- /dev/null +++ b/wai/ops-conformance/certificates/wai.video.int_hyper/13e8b0d18e001eb9f0160309a02755b35a14f71ba0bcaa13f373e32b931ab818.json @@ -0,0 +1 @@ +{"capability":"wai.video.int_hyper","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"c3a28ef54396808853b68f2ffef651e004fd6ff88a048c76ee614f8ed8f1c67d","inputs":[{"hi":"3222701620144925","kind":"data","lo":"-3222701620144925","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"h_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"63","hi":"2565270489635360300","lo":"-2565270489635360300"},"convT.term":{"bits":"60","hi":"512409557603043075","lo":"-512409557603043075"},"rq.p":{"bits":"81","hi":"667884053450150128295400","lo":"-667884053450150128295400"},"rq.q":{"bits":"57","hi":"39808991757044203","lo":"-39808991757044204"},"rq.t":{"bits":"63","hi":"2565270489635360300","lo":"-2565270489635360300"},"rq.y":{"bits":"57","hi":"39808991757044187","lo":"-39808991757044220"}},"k_c":"0","mac":{"a_bits":["53"],"w_bits":"9"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"55","hi":"14081484025732482","lo":"-14081484025732482","policy":"check","result":{"bits":"57","hi":"39808991757044187","lo":"-39808991757044220"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"leaky.p":{"bits":"64","hi":"-655","lo":"-9223372036854775710"}},"npu_flags":[],"op":"leaky","out":[{"bits":"52","hi":"1601279867509509","lo":"-140737488355328","policy":"check","result":{"bits":"55","hi":"14081484025732482","lo":"-140737488355328"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"conv.acc":{"bits":"63","hi":"3416621454807471888","lo":"-3185392888939409270"},"conv.term":{"bits":"59","hi":"254603498934011931","lo":"-256204778801521440"},"rq.p":{"bits":"81","hi":"606252144183947426750496","lo":"-559793427871021368369507"},"rq.q":{"bits":"57","hi":"36135443698403085","lo":"-33366288415850483"},"rq.t":{"bits":"63","hi":"3416621454807471888","lo":"-3185392888939409270"},"rq.y":{"bits":"57","hi":"36135443698403074","lo":"-33366288415850488"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"9"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"57","hi":"36135443698403074","lo":"-33366288415850488","policy":"derived","result":{"bits":"57","hi":"36135443698403074","lo":"-33366288415850488"},"tensor":"3"}],"saturated":false}],"scalars":[]},{"graph_sha256":"f8ad13b9e3ed1624e4b1cfe2ffe6ac8b391738f01263ec118324a1c8a8bac136","inputs":[{"hi":"1601279867509509","kind":"data","lo":"-1601279867509509","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"63","hi":"2717371935163636773","lo":"-2717371935163636773"},"convT.term":{"bits":"59","hi":"256204778801521440","lo":"-256204778801521440"},"rq.p":{"bits":"80","hi":"538917354297457935731679","lo":"-538917354297457935731679"},"rq.q":{"bits":"56","hi":"32121977466193314","lo":"-32121977466193315"},"rq.t":{"bits":"63","hi":"2717371935163636773","lo":"-2717371935163636773"},"rq.y":{"bits":"56","hi":"32121977466193330","lo":"-32121977466193299"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"9"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"40","hi":"283323814454","lo":"-283323814454","policy":"check","result":{"bits":"56","hi":"32121977466193330","lo":"-32121977466193299"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"74","hi":"8191859483341710468646","lo":"0"},"igdn.gx2":{"bits":"89","hi":"291308480943618803505442964","lo":"0"},"igdn.r":{"bits":"38","hi":"90508891736","lo":"2931"},"igdn.term":{"bits":"73","hi":"4445014662835980278098","lo":"0"},"igdn.x2":{"bits":"78","hi":"80272383836764619318116","lo":"0"},"igdn.xr":{"bits":"76","hi":"25643324448647637952144","lo":"-25643324448647637952144"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"52","hi":"1611350810072462","lo":"-1611350810072462","policy":"check","result":{"bits":"64","hi":"6260577257970614734","lo":"-6260577257970614735"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"63","hi":"2357406235136011906","lo":"-2357406235136011906"},"convT.term":{"bits":"59","hi":"256204778801521458","lo":"-256204778801521458"},"rq.p":{"bits":"80","hi":"509275183788902924076992","lo":"-509275183788902924076992"},"rq.q":{"bits":"56","hi":"30355166422659332","lo":"-30355166422659333"},"rq.t":{"bits":"63","hi":"2357406235136011906","lo":"-2357406235136011906"},"rq.y":{"bits":"56","hi":"30355166422659330","lo":"-30355166422659335"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"9"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"56","hi":"30355166422659330","lo":"-30355166422659335","policy":"derived","result":{"bits":"56","hi":"30355166422659330","lo":"-30355166422659335"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"14","hi":"4096","lo":"0","policy":"derived","result":{"bits":"14","hi":"4096","lo":"0"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"4","intermediates":{"rq.p":{"bits":"21","hi":"1046528","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"14","hi":"4096","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"5"}],"saturated":false}],"scalars":[]}],"lowering":"whm1/1","set_sha256":"13e8b0d18e001eb9f0160309a02755b35a14f71ba0bcaa13f373e32b931ab818","verdict":{"acc32":false,"acc32_first_failure":{"bits":"53","graph":"h_s","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.world.model/34986fa89648e03500ade7804e9267adc860202c114bc567fa83ed5693bd38fb.json b/wai/ops-conformance/certificates/wai.world.model/34986fa89648e03500ade7804e9267adc860202c114bc567fa83ed5693bd38fb.json new file mode 100644 index 000000000..5ea72f3d9 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.world.model/34986fa89648e03500ade7804e9267adc860202c114bc567fa83ed5693bd38fb.json @@ -0,0 +1 @@ +{"capability":"wai.world.model","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"923c08d904902ca266a206d048d6960455d99f4fb9e9d29f632a8185ecb7765f","inputs":[{"hi":"9223372036854775807","kind":"data","lo":"-9223372036854775808","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"T","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{},"npu_flags":[],"op":"concat","out":[{"bits":"46","hi":"17880157638461","lo":"-17880157638461","policy":"check","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"5","intermediates":{"conv.acc":{"bits":"63","hi":"2989222634155548441","lo":"-2989222634155548441"},"conv.term":{"bits":"57","hi":"36600682685929667","lo":"-36600682685929667"},"rq.p":{"bits":"73","hi":"3872263095585531040515","lo":"-3872263095585531040515"},"rq.q":{"bits":"49","hi":"230804866289230","lo":"-230804866289231"},"rq.t":{"bits":"63","hi":"2989222634155548441","lo":"-2989222634155548441"},"rq.y":{"bits":"49","hi":"230804866289094","lo":"-230804866289367"}},"k_c":"0","mac":{"a_bits":["46"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"49","hi":"230804866289094","lo":"-230804866289367","policy":"check","result":{"bits":"49","hi":"230804866289094","lo":"-230804866289367"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"6","intermediates":{"leaky.p":{"bits":"58","hi":"-410","lo":"-94629995178640470"}},"npu_flags":[],"op":"leaky","out":[{"bits":"46","hi":"20860183911538","lo":"-20860183911538","policy":"check","result":{"bits":"49","hi":"230804866289094","lo":"-23103026166661"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"7","intermediates":{"conv.acc":{"bits":"63","hi":"3366207877804887060","lo":"-3366207877804887060"},"conv.term":{"bits":"57","hi":"42700796466918286","lo":"-42700796466918286"},"rq.p":{"bits":"73","hi":"4183506629270255700072","lo":"-4183506629270255700072"},"rq.q":{"bits":"49","hi":"249356426553145","lo":"-249356426553146"},"rq.t":{"bits":"63","hi":"3366207877804887060","lo":"-3366207877804887060"},"rq.y":{"bits":"49","hi":"249356426553386","lo":"-249356426552905"}},"k_c":"0","mac":{"a_bits":["46"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"49","hi":"249356426553386","lo":"-249356426552905","policy":"derived","result":{"bits":"49","hi":"249356426553386","lo":"-249356426552905"},"tensor":"8"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"8","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"14","hi":"4096","lo":"-4096","policy":"derived","result":{"bits":"14","hi":"4096","lo":"-4096"},"tensor":"9"}],"saturated":false}],"scalars":[{"hi":"9223372036854775807","index":"0","lo":"-9223372036854775808"},{"hi":"9223372036854775807","index":"1","lo":"-9223372036854775808"},{"hi":"9223372036854775807","index":"2","lo":"-9223372036854775808"},{"hi":"9223372036854775807","index":"3","lo":"-9223372036854775808"}]},{"graph_sha256":"e891e6c16c57a33e7998a6388d1981ec0b609937338e839dae727be4024058e1","inputs":[{"hi":"11733853450240","kind":"data","lo":"-11733853450240","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"61","hi":"747505134047539200","lo":"-747505134047539200"},"convT.term":{"bits":"56","hi":"24019198012641280","lo":"-24019198012641280"},"rq.p":{"bits":"71","hi":"1154881245874626723840","lo":"-1154881245874626723840"},"rq.q":{"bits":"47","hi":"68836286418117","lo":"-68836286418118"},"rq.t":{"bits":"61","hi":"747505134047539200","lo":"-747505134047539200"},"rq.y":{"bits":"47","hi":"68836286418109","lo":"-68836286418126"}},"k_c":"0","mac":{"a_bits":["45"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"79494954953","lo":"-79494954953","policy":"check","result":{"bits":"47","hi":"68836286418109","lo":"-68836286418126"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"79","hi":"155096950720018892532062","lo":"0"},"igdn.gx2":{"bits":"90","hi":"616721236396032309570508519","lo":"0"},"igdn.r":{"bits":"40","hi":"393823501990","lo":"4481"},"igdn.term":{"bits":"74","hi":"9410419256531254723671","lo":"0"},"igdn.x2":{"bits":"74","hi":"6319447862979499232209","lo":"0"},"igdn.xr":{"bits":"76","hi":"31306981550127755856470","lo":"-31306981550127755856470"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"45","hi":"11733853450240","lo":"-11733853450240","policy":"check","result":{"bits":"64","hi":"7643306042511659144","lo":"-7643306042511659145"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"61","hi":"669627548698296320","lo":"-669627548698296320"},"convT.term":{"bits":"56","hi":"24019198012641280","lo":"-24019198012641280"},"rq.p":{"bits":"71","hi":"974341466169087078400","lo":"-974341466169087078400"},"rq.q":{"bits":"47","hi":"58075276980941","lo":"-58075276980942"},"rq.t":{"bits":"61","hi":"669627548698296320","lo":"-669627548698296320"},"rq.y":{"bits":"47","hi":"58075276980954","lo":"-58075276980929"}},"k_c":"0","mac":{"a_bits":["45"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"76998216135","lo":"-76998216135","policy":"check","result":{"bits":"47","hi":"58075276980954","lo":"-58075276980929"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{"igdn.N":{"bits":"78","hi":"139206082570665154676879","lo":"0"},"igdn.gx2":{"bits":"91","hi":"657365202479778746273711550","lo":"0"},"igdn.r":{"bits":"40","hi":"373103313534","lo":"4237"},"igdn.term":{"bits":"75","hi":"10030596961666545811061","lo":"0"},"igdn.x2":{"bits":"74","hi":"5928725287972174338225","lo":"0"},"igdn.xr":{"bits":"76","hi":"28728289576175602671090","lo":"-28728289576175602671090"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"45","hi":"11733853450240","lo":"-11733853450240","policy":"check","result":{"bits":"64","hi":"7013742572308496745","lo":"-7013742572308496746"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{"convT.acc":{"bits":"61","hi":"751037023936061440","lo":"-751037023936061440"},"convT.term":{"bits":"56","hi":"24019198012641280","lo":"-24019198012641280"},"rq.p":{"bits":"72","hi":"1451889483115377623040","lo":"-1451889483115377623040"},"rq.q":{"bits":"48","hi":"86539356894217","lo":"-86539356894218"},"rq.t":{"bits":"61","hi":"751037023936061440","lo":"-751037023936061440"},"rq.y":{"bits":"48","hi":"86539356894662","lo":"-86539356893773"}},"k_c":"0","mac":{"a_bits":["45"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"48","hi":"86539356894662","lo":"-86539356893773","policy":"derived","result":{"bits":"48","hi":"86539356894662","lo":"-86539356893773"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"14","hi":"4096","lo":"0","policy":"derived","result":{"bits":"14","hi":"4096","lo":"0"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"6","intermediates":{"rq.p":{"bits":"21","hi":"1046528","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"14","hi":"4096","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"7"}],"saturated":false}],"scalars":[]}],"lowering":"world/1","set_sha256":"34986fa89648e03500ade7804e9267adc860202c114bc567fa83ed5693bd38fb","verdict":{"acc32":false,"acc32_first_failure":{"bits":"64","graph":"T","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.world.model/5291a52bdbf2279c3350eda96b515bde66d73700c73ccb207e714cb2c6a4c45e.json b/wai/ops-conformance/certificates/wai.world.model/5291a52bdbf2279c3350eda96b515bde66d73700c73ccb207e714cb2c6a4c45e.json new file mode 100644 index 000000000..f95bca1e0 --- /dev/null +++ b/wai/ops-conformance/certificates/wai.world.model/5291a52bdbf2279c3350eda96b515bde66d73700c73ccb207e714cb2c6a4c45e.json @@ -0,0 +1 @@ +{"capability":"wai.world.model","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"c17f643e7fce0e0061ff4395afb573f839bab1f1e473225917dabfad0a0ff9bf","inputs":[{"hi":"9223372036854775807","kind":"data","lo":"-9223372036854775808","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"T","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"concat","out":[{"bits":"51","hi":"683212743470724","lo":"-683212743470724","policy":"check","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{"conv.acc":{"bits":"64","hi":"4943044199010688140","lo":"-4943044199010688140"},"conv.term":{"bits":"59","hi":"204963823041217200","lo":"-204963823041217200"},"rq.p":{"bits":"75","hi":"15103937159561832910176","lo":"-15103937159561832910176"},"rq.q":{"bits":"63","hi":"3687484658096150612","lo":"-3687484658096150613"},"rq.t":{"bits":"64","hi":"4943044199010688140","lo":"-4943044199010688140"},"rq.y":{"bits":"63","hi":"3687484658096149674","lo":"-3687484658096151551"}},"k_c":"0","mac":{"a_bits":["51"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"55","hi":"14081484025732482","lo":"-14081484025732482","policy":"check","result":{"bits":"63","hi":"3687484658096149674","lo":"-3687484658096151551"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"5","intermediates":{"leaky.p":{"bits":"64","hi":"-655","lo":"-9223372036854775710"}},"npu_flags":[],"op":"leaky","out":[{"bits":"54","hi":"8119165525400330","lo":"-2251799813685248","policy":"check","result":{"bits":"55","hi":"14081484025732482","lo":"-2251799813685248"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"6","intermediates":{"conv.acc":{"bits":"64","hi":"4943144607903789256","lo":"-3446966351416443346"},"conv.term":{"bits":"62","hi":"2305843009213693720","lo":"-1769978084537271940"},"rq.p":{"bits":"75","hi":"16732544497754326631560","lo":"-11667981099544660726210"},"rq.q":{"bits":"63","hi":"4085093871522052400","lo":"-2848628198131020686"},"rq.t":{"bits":"64","hi":"4943144607903789256","lo":"-3446966351416443346"},"rq.y":{"bits":"63","hi":"4085093871522052157","lo":"-2848628198131020929"}},"k_c":"0","mac":{"a_bits":["54"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"63","hi":"4085093871522052157","lo":"-2848628198131020929","policy":"derived","result":{"bits":"63","hi":"4085093871522052157","lo":"-2848628198131020929"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"7","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"10","hi":"256","lo":"-256","policy":"derived","result":{"bits":"10","hi":"256","lo":"-256"},"tensor":"8"}],"saturated":false}],"scalars":[{"hi":"9223372036854775807","index":"0","lo":"-9223372036854775808"},{"hi":"9223372036854775807","index":"1","lo":"-9223372036854775808"},{"hi":"9223372036854775807","index":"2","lo":"-9223372036854775808"}]},{"graph_sha256":"4c40ffd1aabd9fd3fac2fe5d15a894ea987b52518d4fef63254e935bbc6991f3","inputs":[{"hi":"1797928272291379","kind":"data","lo":"-1797928272291379","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"63","hi":"3042094636717013268","lo":"-3042094636717013268"},"convT.term":{"bits":"60","hi":"512409557603043015","lo":"-512409557603043015"},"rq.p":{"bits":"74","hi":"8949842421221453034456","lo":"-8949842421221453034456"},"rq.q":{"bits":"62","hi":"2185020122368518807","lo":"-2185020122368518808"},"rq.t":{"bits":"63","hi":"3042094636717013268","lo":"-3042094636717013268"},"rq.y":{"bits":"62","hi":"2185020122368518795","lo":"-2185020122368518820"}},"k_c":"0","mac":{"a_bits":["52"],"w_bits":"10"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"37","hi":"37348641346","lo":"-37348641346","policy":"check","result":{"bits":"62","hi":"2185020122368518795","lo":"-2185020122368518820"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"73","hi":"3318386309878178475269","lo":"0"},"igdn.gx2":{"bits":"82","hi":"1364232748163513596498248","lo":"0"},"igdn.r":{"bits":"37","hi":"57605436461","lo":"141"},"igdn.term":{"bits":"72","hi":"1332258543128431246580","lo":"0"},"igdn.x2":{"bits":"72","hi":"1394921010392140691716","lo":"0"},"igdn.xr":{"bits":"72","hi":"2151484785961680516506","lo":"-2151484785961680516506"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"64","hi":"8404237445162814517","lo":"-8404237445162814518","policy":"derived","result":{"bits":"64","hi":"8404237445162814517","lo":"-8404237445162814518"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"10","hi":"256","lo":"0","policy":"derived","result":{"bits":"10","hi":"256","lo":"0"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"3","intermediates":{"rq.p":{"bits":"17","hi":"65408","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"10","hi":"256","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"4"}],"saturated":false}],"scalars":[]}],"lowering":"world/1","set_sha256":"5291a52bdbf2279c3350eda96b515bde66d73700c73ccb207e714cb2c6a4c45e","verdict":{"acc32":false,"acc32_first_failure":{"bits":"64","graph":"T","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/certificates/wai.world.model/da046216ff9495a47fbfdf14788510bc951a266896b47234bb174cef8769ab88.json b/wai/ops-conformance/certificates/wai.world.model/da046216ff9495a47fbfdf14788510bc951a266896b47234bb174cef8769ab88.json new file mode 100644 index 000000000..73104516e --- /dev/null +++ b/wai/ops-conformance/certificates/wai.world.model/da046216ff9495a47fbfdf14788510bc951a266896b47234bb174cef8769ab88.json @@ -0,0 +1 @@ +{"capability":"wai.world.model","certificate":"wai-ops/1 bounds","graphs":[{"graph_sha256":"18e66cbe2d937c5aa81b0d1f88eba57fa0a1baf305283025540e56a0523143ee","inputs":[{"hi":"9223372036854775807","kind":"data","lo":"-9223372036854775808","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"T","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{},"npu_flags":[],"op":"fill","out":[{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808","policy":"derived","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{},"npu_flags":[],"op":"concat","out":[{"bits":"46","hi":"18542385699145","lo":"-18542385699145","policy":"check","result":{"bits":"64","hi":"9223372036854775807","lo":"-9223372036854775808"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{"conv.acc":{"bits":"63","hi":"2586996567973312110","lo":"-2586996567973312110"},"conv.term":{"bits":"57","hi":"37956263526149815","lo":"-37956263526149815"},"rq.p":{"bits":"74","hi":"5824415524546952872000","lo":"-5824415524546952872000"},"rq.q":{"bits":"50","hi":"347162218364891","lo":"-347162218364892"},"rq.t":{"bits":"63","hi":"2586996567973312110","lo":"-2586996567973312110"},"rq.y":{"bits":"50","hi":"347162218365489","lo":"-347162218364294"}},"k_c":"0","mac":{"a_bits":["46"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"50","hi":"347162218365489","lo":"-347162218364294","policy":"check","result":{"bits":"50","hi":"347162218365489","lo":"-347162218364294"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"5","intermediates":{"leaky.p":{"bits":"58","hi":"-410","lo":"-142336509529360540"}},"npu_flags":[],"op":"leaky","out":[{"bits":"46","hi":"20860183911538","lo":"-20860183911538","policy":"check","result":{"bits":"50","hi":"347162218365489","lo":"-34750124396817"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"6","intermediates":{"conv.acc":{"bits":"63","hi":"2668851929642171720","lo":"-2668851929642171720"},"conv.term":{"bits":"57","hi":"42700796466918286","lo":"-42700796466918286"},"rq.p":{"bits":"73","hi":"4350228812198211195904","lo":"-4350228812198211195904"},"rq.q":{"bits":"49","hi":"259293843042743","lo":"-259293843042744"},"rq.t":{"bits":"63","hi":"2668851929642171720","lo":"-2668851929642171720"},"rq.y":{"bits":"49","hi":"259293843043269","lo":"-259293843042218"}},"k_c":"0","mac":{"a_bits":["46"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv","out":[{"bits":"49","hi":"259293843043269","lo":"-259293843042218","policy":"derived","result":{"bits":"49","hi":"259293843043269","lo":"-259293843042218"},"tensor":"7"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"7","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"14","hi":"4096","lo":"-4096","policy":"derived","result":{"bits":"14","hi":"4096","lo":"-4096"},"tensor":"8"}],"saturated":false}],"scalars":[{"hi":"9223372036854775807","index":"0","lo":"-9223372036854775808"},{"hi":"9223372036854775807","index":"1","lo":"-9223372036854775808"},{"hi":"9223372036854775807","index":"2","lo":"-9223372036854775808"}]},{"graph_sha256":"53cece504f3bd9e315a330f98554b77696770c35363e8992c7ab7ee04abcd3fd","inputs":[{"hi":"11733853450240","kind":"data","lo":"-11733853450240","max_h":"0","max_w":"0","policy":"check","tensor":"0"}],"name":"g_s","nodes":[{"acc32_params":[],"fits":["acc64"],"index":"0","intermediates":{"convT.acc":{"bits":"61","hi":"1002024149236695040","lo":"-1002024149236695040"},"convT.term":{"bits":"56","hi":"24019198012641280","lo":"-24019198012641280"},"rq.p":{"bits":"72","hi":"1519554157098600611840","lo":"-1519554157098600611840"},"rq.q":{"bits":"48","hi":"90572485750830","lo":"-90572485750831"},"rq.t":{"bits":"61","hi":"1002024149236695040","lo":"-1002024149236695040"},"rq.y":{"bits":"48","hi":"90572485751698","lo":"-90572485749963"}},"k_c":"0","mac":{"a_bits":["45"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"71304016834","lo":"-71304016834","policy":"check","result":{"bits":"48","hi":"90572485751698","lo":"-90572485749963"},"tensor":"1"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"1","intermediates":{"igdn.N":{"bits":"78","hi":"102521099954890836559322","lo":"0"},"igdn.gx2":{"bits":"91","hi":"766549220605517427823354564","lo":"0"},"igdn.r":{"bits":"40","hi":"320189162769","lo":"4541"},"igdn.term":{"bits":"75","hi":"11696612863243368954824","lo":"0"},"igdn.x2":{"bits":"74","hi":"5084262816663355383556","lo":"0"},"igdn.xr":{"bits":"76","hi":"22830773452145142053346","lo":"-22830773452145142053346"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"45","hi":"11733853450240","lo":"-11733853450240","policy":"check","result":{"bits":"64","hi":"5573919299840122571","lo":"-5573919299840122572"},"tensor":"2"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"2","intermediates":{"convT.acc":{"bits":"61","hi":"773202273103564800","lo":"-773202273103564800"},"convT.term":{"bits":"56","hi":"24019198012641280","lo":"-24019198012641280"},"rq.p":{"bits":"72","hi":"1211560897467097128960","lo":"-1211560897467097128960"},"rq.q":{"bits":"48","hi":"72214656917279","lo":"-72214656917280"},"rq.t":{"bits":"61","hi":"773202273103564800","lo":"-773202273103564800"},"rq.y":{"bits":"48","hi":"72214656917664","lo":"-72214656916895"}},"k_c":"0","mac":{"a_bits":["45"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"38","hi":"80588457227","lo":"-80588457227","policy":"check","result":{"bits":"48","hi":"72214656917664","lo":"-72214656916895"},"tensor":"3"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"3","intermediates":{"igdn.N":{"bits":"78","hi":"114908719735727836101099","lo":"0"},"igdn.gx2":{"bits":"90","hi":"600098242591706216137009129","lo":"0"},"igdn.r":{"bits":"40","hi":"338981887031","lo":"4654"},"igdn.term":{"bits":"74","hi":"9156772500483798464004","lo":"0"},"igdn.x2":{"bits":"74","hi":"6494499438228008529529","lo":"0"},"igdn.xr":{"bits":"76","hi":"27318027303725489523037","lo":"-27318027303725489523037"}},"k_c":"0","npu_flags":[],"op":"igdn","out":[{"bits":"45","hi":"11733853450240","lo":"-11733853450240","policy":"check","result":{"bits":"64","hi":"6669440259698605840","lo":"-6669440259698605841"},"tensor":"4"}],"saturated":false},{"acc32_params":[],"fits":["acc64"],"index":"4","intermediates":{"convT.acc":{"bits":"61","hi":"810879676532285440","lo":"-810879676532285440"},"convT.term":{"bits":"56","hi":"24019198012641280","lo":"-24019198012641280"},"rq.p":{"bits":"72","hi":"1563034936702154752000","lo":"-1563034936702154752000"},"rq.q":{"bits":"48","hi":"93164142173657","lo":"-93164142173658"},"rq.t":{"bits":"61","hi":"810879676532285440","lo":"-810879676532285440"},"rq.y":{"bits":"48","hi":"93164142174556","lo":"-93164142172759"}},"k_c":"0","mac":{"a_bits":["45"],"w_bits":"12"},"npu_flags":["rq_floor_mult","rq_post_bias"],"op":"conv_transpose","out":[{"bits":"48","hi":"93164142174556","lo":"-93164142172759","policy":"derived","result":{"bits":"48","hi":"93164142174556","lo":"-93164142172759"},"tensor":"5"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"5","intermediates":{},"npu_flags":[],"op":"clamp","out":[{"bits":"14","hi":"4096","lo":"0","policy":"derived","result":{"bits":"14","hi":"4096","lo":"0"},"tensor":"6"}],"saturated":false},{"acc32_params":[],"fits":["acc32","acc64"],"index":"6","intermediates":{"rq.p":{"bits":"21","hi":"1046528","lo":"0"},"rq.q":{"bits":"9","hi":"255","lo":"0"},"rq.t":{"bits":"14","hi":"4096","lo":"0"},"rq.y":{"bits":"9","hi":"255","lo":"0"}},"npu_flags":[],"op":"rescale","out":[{"bits":"9","hi":"255","lo":"0","policy":"derived","result":{"bits":"9","hi":"255","lo":"0"},"tensor":"7"}],"saturated":false}],"scalars":[]}],"lowering":"world/1","set_sha256":"da046216ff9495a47fbfdf14788510bc951a266896b47234bb174cef8769ab88","verdict":{"acc32":false,"acc32_first_failure":{"bits":"64","graph":"T","index":"0","key":"range","where":"input"},"acc64":true,"npu":false,"npu_flags":["rq_floor_mult","rq_post_bias"],"npu_reasons":["acc32","op:igdn"]}} \ No newline at end of file diff --git a/wai/ops-conformance/graphs/load.jsonl b/wai/ops-conformance/graphs/load.jsonl index acd6a4574..53ba955cb 100644 --- a/wai/ops-conformance/graphs/load.jsonl +++ b/wai/ops-conformance/graphs/load.jsonl @@ -58,3 +58,6 @@ {"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000200000080020000f7ffffffffffffff090000000000000002000000800000000000000000000000000000000000000018010100000000000100000024000000010000000000000002000000000000000100ffff00000000000000000000000000000000","id":"load/step5/57","load":"model_mismatch","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-1","0","-1","1"],"shape":["2","1","2"]}]},"inputs":[{"data":["-9","9","3","-4"],"shape":["2","1","2"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000200000080020000f7ffffffffffffff0900000000000000020000008000000000000000000000000000000000000000180101000000000001000000280000000100000000000000040000000000000001000000ffffffff00000000000000000000000000000000","id":"load/step5/58","load":"ok","profiles":["acc64"]} {"decodes":[{"expect":{"refuse":"geometry_mismatch"},"inputs":[{"data":["2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2"],"shape":["1","4","4"]}],"scalars":["1"]},{"expect":{"refuse":"geometry_mismatch"},"inputs":[{"data":["2","2","2","2","2","2","2","2","2","2","2","2","2","2","2","2"],"shape":["1","4","4"]}],"scalars":["3"]}],"graph":"5748473101010000020000000100000001000100010000000000000400000000010000000000000003000000000000000000000004000000040000000000000000000000000000000000000000000000010000000100000080020000f7ffffffffffffff0900000000000000010000008000000000000000000000000000000000000000140101000000000001000000200000000100000000000000000000000000000000000000040000000000000001000000","id":"load/crop_plan/59","load":"ok","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"5748473101010000030000000200000001000100010000000000000400000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000020000000200000080020000f7ffffffffffffff09000000000000000300000080000000000000000000000000000000000000000300000080020000f7ffffffffffffffffffffffffffffff010101000000000001000000330000000300000001000000010000000100000001000000000000000000000001000000010000000000000100000000010102030405060c010100010000000200000000000000","id":"load/step8/60","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[{"expect":{"refuse":"field_range"},"inputs":[{"data":["-9","9","3","-3"],"shape":["2","1","2"]}],"scalars":["0"]},{"expect":{"outputs":[{"data":["0","0","0","0","0","0"],"shape":["3","1","2"]}]},"inputs":[{"data":["0","-1","0","0"],"shape":["2","1","2"]}],"scalars":["0"]}],"graph":"5748473101010000030000000200000001000100010000000000000400000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000020000000200000080020000f7ffffffffffffff09000000000000000300000080000000000000000000000000000000000000000300000080020000f7ffffffffffffff0000000000000000010101000000000001000000330000000300000001000000010000000100000001000000000000000000000001000000010000000000000100000000010102030405060c010100010000000200000000000000","id":"load/step8/61","load":"ok","profiles":["acc64"]} +{"decodes":[],"graph":"57484731010100000300000002000000010001000100000000000004000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000200000002000000800200000000000000000080ffffffffffffff7f030000008000000000000000000000000000000000000000030000008000000000000000000000000000000000000000010101000000000001000000330000000300000001000000010000000100000001000000000000000000000001000000010000000000000100000000010101010101010c010100010000000200000000000000","id":"load/step8/62","load":"model_mismatch","profiles":["acc32","acc64"]} diff --git a/wai/ops-conformance/sets/claim_acc32/int_synth.json b/wai/ops-conformance/sets/claim_acc32/int_synth.json new file mode 100644 index 000000000..b3ef85166 --- /dev/null +++ b/wai/ops-conformance/sets/claim_acc32/int_synth.json @@ -0,0 +1 @@ +{"layers":[{"in_ch":1,"out_ch":2,"k":1,"stride":1,"pad":0,"weight":[1,1],"bias":[129,129],"shift":8},{"in_ch":2,"out_ch":3,"k":1,"stride":1,"pad":0,"weight":[1073741824,0,0,1073741824,0,0],"bias":[0,0,0],"shift":0}]} diff --git a/wai/ops-conformance/sets/overflow_acc64/int_synth.json b/wai/ops-conformance/sets/overflow_acc64/int_synth.json new file mode 100644 index 000000000..e23eef79f --- /dev/null +++ b/wai/ops-conformance/sets/overflow_acc64/int_synth.json @@ -0,0 +1 @@ +{"layers":[{"in_ch":1,"out_ch":1,"k":1,"stride":1,"pad":0,"weight":[331720249],"bias":[0],"shift":0,"relu":true},{"in_ch":1,"out_ch":3,"k":1,"stride":1,"pad":0,"weight":[218934409,0,0],"bias":[1,0,0],"shift":0}]} diff --git a/wai/ops-conformance/vectors/chscale.jsonl b/wai/ops-conformance/vectors/chscale.jsonl index 9ee980f65..80638ed20 100644 --- a/wai/ops-conformance/vectors/chscale.jsonl +++ b/wai/ops-conformance/vectors/chscale.jsonl @@ -62,3 +62,6 @@ {"decodes":[{"expect":{"outputs":[{"data":["-22","0","23","9","-9","15"],"shape":["2","1","3"]}]},"inputs":[{"data":["-9","0","9","3","-3","5"],"shape":["2","1","3"]}],"scalars":["2"]}],"graph":"5748473101010000020000000100000001000100010000000000000400000000010000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000010000000200000080020000f7ffffffffffffff09000000000000000200000080000000000000000000000000000000000000000301010000000000010000002c0000000000000004000000010401000100000002000000030000000400000005000000060000000700000008000000","id":"chscale/scalar/61","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"refuse":"field_range"},"inputs":[{"data":["-9","0","9","3","-3","5"],"shape":["2","1","3"]}],"scalars":["0"]}],"graph":"5748473101010000020000000100000001000100010000000000000400000000010000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000010000000200000080020000f7ffffffffffffff09000000000000000200000080000000000000000000000000000000000000000301010000000000010000002c0000000000000004000000010401000100000002000000030000000400000005000000060000000700000008000000","id":"chscale/scalar/62","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"refuse":"field_range"},"inputs":[{"data":["-9","0","9","3","-3","5"],"shape":["2","1","3"]}],"scalars":["3"]}],"graph":"5748473101010000020000000100000001000100010000000000000400000000010000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000010000000200000080020000f7ffffffffffffff09000000000000000200000080000000000000000000000000000000000000000301010000000000010000002c0000000000000004000000010401000100000002000000030000000400000005000000060000000700000008000000","id":"chscale/scalar/63","load":"ok","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"5748473101010000020000000100000001000100010000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000000000000000004000000000000000400100000080000000000000000000000000000000000000000301010000000000010000001000000000000000010000000004000002000000","id":"chscale/step8_q/64","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["-1","0"],"shape":["1","1","2"]}]},"inputs":[{"data":["-1","0"],"shape":["1","1","2"]}],"scalars":["0"]}],"graph":"5748473101010000020000000100000001000100010000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000ffffffffffffffff000000000000000001000000800000000000000000000000000000000000000003010100000000000100000014000000000000000100000000081f000000008000000000","id":"chscale/acc32_param/65","load":"ok","profiles":["acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["0","0"],"shape":["1","1","2"]}]},"inputs":[{"data":["0","5"],"shape":["1","1","2"]}],"scalars":["0"]}],"graph":"5748473101010000020000000100000001000100010000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000000000000000000005000000000000000100000080000000000000000000000000000000000000000301010000000000010000001000000000000000010000000004400001000000","id":"chscale/acc32_param/66","load":"ok","profiles":["acc64"]} diff --git a/wai/ops-conformance/vectors/conv.jsonl b/wai/ops-conformance/vectors/conv.jsonl index f4cff52bf..550ee2c6d 100644 --- a/wai/ops-conformance/vectors/conv.jsonl +++ b/wai/ops-conformance/vectors/conv.jsonl @@ -120,3 +120,6 @@ {"decodes":[{"expect":{"refuse":"field_range"},"inputs":[{"data":["-4","-4"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000f6ffffffffffffff14000000000000000100000080020000faffffffffffffff1e000000000000000101010000000000010000002e00000001000000010000000100000001000000010000000000000000000000010000000100000000000001000000000002","id":"conv/check/119","load":"ok","profiles":["acc64"]} {"decodes":[{"expect":{"refuse":"field_range"},"inputs":[{"data":["16","16"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000f6ffffffffffffff14000000000000000100000080020000faffffffffffffff1e000000000000000101010000000000010000002e00000001000000010000000100000001000000010000000000000000000000010000000100000000000001000000000002","id":"conv/check/120","load":"ok","profiles":["acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-6","-6","27","30"],"shape":["1","1","4"]}]},"inputs":[{"data":["-100","-3","9","100"],"shape":["1","1","4"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080010000f6ffffffffffffff14000000000000000100000080010000faffffffffffffff1e000000000000000101010000000000010000002e00000001000000010000000100000001000000010000000000000000000000010000000100000000000001000000000003","id":"conv/check/121","load":"ok","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000000000000000002000000000000000200100000080000000000000000000000000000000000000000101010000000000010000003600000001000000010000000100000001000000010000000000000000000000010000000100000000020101040400000400000000ffffffff01","id":"conv/step8_q/122","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["-1","9223372036854775803"],"shape":["1","1","2"]}]},"inputs":[{"data":["0","2305843009213693951"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000000000000000000ffffffffffffff1f0100000080000000000000000000000000000000000000000101010000000000010000003600000001000000010000000100000001000000010000000000000000000000010000000100000000020101040400000400000000ffffffff01","id":"conv/step8_q/123","load":"ok","profiles":["acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["-2147483648","0"],"shape":["1","1","2"]}]},"inputs":[{"data":["-1","0"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000ffffffffffffffff0000000000000000010000008000000000000000000000000000000000000000010101000000000001000000350000000100000001000000010000000100000001000000000000000000000001000000080000000000000100000000000000008000000000","id":"conv/acc32_param/124","load":"ok","profiles":["acc64"]} diff --git a/wai/ops-conformance/vectors/conv_transpose.jsonl b/wai/ops-conformance/vectors/conv_transpose.jsonl index 6f9729506..923106b9b 100644 --- a/wai/ops-conformance/vectors/conv_transpose.jsonl +++ b/wai/ops-conformance/vectors/conv_transpose.jsonl @@ -111,3 +111,6 @@ {"decodes":[{"expect":{"outputs":[{"data":["-49","128","-194","-110","67","1","-121","47","122","137","-170","269","-26","31","13","-230","98","70","229","-62","-5","7","-140","-20","-125","-73","19","98","1","-7","-2","-14","5","73","152","-95","-34","7","104","-107","125","-142","-73","-152","20","-98","-95","146","-121","-13","-173","280","-158","43","-14","49","-23","71","227","2","-11","-26","37","41","-40","-10","-2","-47","46","-53","28","-2","-22","-17","-29","62","-37","55","-90","70","-188","90","-4","-110","59","-67","110","-154","136","2","-58","82","-96","4","-127","86","81","-56","10","0","-58","-5","-73","-103","-13","14","98","-37","108","-37","81","94","2","-15","-185","62","5","79","114","-13","-200","4","-67","-201","-1","-43","35","-153","139","6","-40","-26","-46","42","-129","86","86","-37","81","-16","7","13","-51","18","-51","23","12","16","21","-43","6","-63","12","1"],"shape":["2","11","7"]}]},"inputs":[{"data":["-20","-15","-10","-5","0","5","10","15","20","-16","-11","-6","-1","4","9","14","19","-17","-12","-7","-2","3","8","13","18","-18","-13","-8","-3","2"],"shape":["2","5","3"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000200000080020000ecffffffffffffff14000000000000000200000080000000000000000000000000000000000000001101010000000000010000008100000002000000040000000400000002000000020000000100000001000000010000000100000001000000010202010404000003000000feffffff0105000000fbfffffffbfe0104fcff0205fd0003fbfe0104fcff0205fd0003fbfe0104fcff0205fd0003fbfe0104fcff0205fd0003fbfe0104fcff0205fd0003fbfe0104fcff0205fd","id":"conv_transpose/geometry/110","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"refuse":"geometry_mismatch"},"inputs":[{"data":["-20","-15"],"shape":["2","1","1"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000200000080020000ecffffffffffffff14000000000000000200000080000000000000000000000000000000000000001101010000000000010000006500000002000000030000000300000001000000010000000200000002000000000000000000000001000000010202010404000003000000feffffff0105000000fbfffffffbfe0104fcff0205fd0003fbfe0104fcff0205fd0003fbfe0104fcff0205fd0003fbfe01","id":"conv_transpose/geometry/111","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-25","20","133","-32","43","80","-40","65","28","-47","-2","95","-60","30","60","-45","40","25","-30","50","-10","-95"],"shape":["2","1","11"]}]},"inputs":[{"data":["-20","-15","-10","-5","0","5","10","15"],"shape":["2","1","4"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000200000080020000ecffffffffffffff14000000000000000200000080000000000000000000000000000000000000001101010000000000010000005500000002000000010000000500000001000000030000000000000002000000000000000100000001000000010202010404000003000000feffffff0105000000fbfffffffbfe0104fcff0205fd0003fbfe0104fcff0205fd","id":"conv_transpose/geometry/112","load":"ok","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000000000000000002000000000000000200100000080000000000000000000000000000000000000001101010000000000010000003a0000000100000001000000010000000100000001000000000000000000000000000000000000000100000000020101040400000400000000ffffffff01","id":"conv_transpose/step8_q/113","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["-1","9223372036854775803"],"shape":["1","1","2"]}]},"inputs":[{"data":["0","2305843009213693951"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000000000000000000ffffffffffffff1f0100000080000000000000000000000000000000000000001101010000000000010000003a0000000100000001000000010000000100000001000000000000000000000000000000000000000100000000020101040400000400000000ffffffff01","id":"conv_transpose/step8_q/114","load":"ok","profiles":["acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["-2147483648","0"],"shape":["1","1","2"]}]},"inputs":[{"data":["-1","0"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000ffffffffffffffff000000000000000001000000800000000000000000000000000000000000000011010100000000000100000039000000010000000100000001000000010000000100000000000000000000000000000000000000080000000000000100000000000000008000000000","id":"conv_transpose/acc32_param/115","load":"ok","profiles":["acc64"]} diff --git a/wai/ops-conformance/vectors/elu.jsonl b/wai/ops-conformance/vectors/elu.jsonl index c3bffb2ab..6ade96680 100644 --- a/wai/ops-conformance/vectors/elu.jsonl +++ b/wai/ops-conformance/vectors/elu.jsonl @@ -33,3 +33,5 @@ {"decodes":[{"expect":{"outputs":[{"data":["-1","-1","1","1","1","9223372036854775807"],"shape":["1","1","6"]}]},"inputs":[{"data":["0","-1","1","-2861838","-9223372036854775807","9223372036854775807"],"shape":["1","1","6"]}],"scalars":[]}],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000100000000000080ffffffffffffff7f0100000080000000000000000000000000000000000000001c010100000000000100000008000000ffffffffffffffff","id":"elu/zero/32","load":"ok","profiles":["acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["0","0","1","-3855","-3855","9223372036854775807"],"shape":["1","1","6"]}]},"inputs":[{"data":["0","-1","1","-2861838","-9223372036854775807","9223372036854775807"],"shape":["1","1","6"]}],"scalars":[]}],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000100000000000080ffffffffffffff7f0100000080000000000000000000000000000000000000001c0101000000000001000000080000000f0f000000000000","id":"elu/zero/33","load":"ok","profiles":["acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-2","-1","1","3856","3856","9223372036854775807"],"shape":["1","1","6"]}]},"inputs":[{"data":["0","-1","1","-2861838","-9223372036854775807","9223372036854775807"],"shape":["1","1","6"]}],"scalars":[]}],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000100000000000080ffffffffffffff7f0100000080000000000000000000000000000000000000001c010100000000000100000008000000f0f0ffffffffffff","id":"elu/zero/34","load":"ok","profiles":["acc64"]} +{"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000000000000000008000000000000000000100000080000000000000000000000000000000000000001c0101000000000001000000080000000000010000000000","id":"elu/step8/35","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000000000000000008000000000000000000100000080000000000000000000000000000000000000001c0101000000000001000000080000000100000000000000","id":"elu/step8/36","load":"model_mismatch","profiles":["acc32","acc64"]} diff --git a/wai/ops-conformance/vectors/igdn.jsonl b/wai/ops-conformance/vectors/igdn.jsonl index 1d6a97d5a..217f7761a 100644 --- a/wai/ops-conformance/vectors/igdn.jsonl +++ b/wai/ops-conformance/vectors/igdn.jsonl @@ -64,3 +64,5 @@ {"decodes":[{"expect":{"outputs":[{"data":["-32766","0","32765"],"shape":["1","1","3"]}]},"inputs":[{"data":["-46340","0","46340"],"shape":["1","1","3"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000fc4affffffffffff04b50000000000000100000080000000000000000000000000000000000000001201010000000000010000001c0000001f000000100000000400000000000000ffffff7f0000000000000000","id":"igdn/edge/63","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-70368744144896","0","70368744144896"],"shape":["1","1","3"]}]},"inputs":[{"data":["-2147483648","0","2147483648"],"shape":["1","1","3"]}],"scalars":[]}],"graph":"5748473101010000020000000100000001000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000000001000000010000008002000000000080ffffffff00000080000000000100000080000000000000000000000000000000000000001201010000000000010000001c0000001f000000100000000400000000000000ffffff7f0000000000000000","id":"igdn/edge/64","load":"ok","profiles":["acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-70368744079361","0","70368744079360"],"shape":["1","1","3"]}]},"inputs":[{"data":["-2147483647","0","2147483647"],"shape":["1","1","3"]}],"scalars":[]}],"graph":"5748473101010000020000000100000001000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000000001000000010000008002000001000080ffffffffffffff7f000000000100000080000000000000000000000000000000000000001201010000000000010000001c0000001f000000100000000400000000000000ffffff7f0000000000000000","id":"igdn/edge/65","load":"ok","profiles":["acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["0","1"],"shape":["1","1","2"]}]},"inputs":[{"data":["0","1"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"5748473101010000020000000100000001000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000000001000000010000008002000000000000000000000100000000000000010000008000000000000000000000000000000000000000120101000000000001000000200000001f00000000000000080000000000000000000080000000000100000000000000","id":"igdn/acc32_param/66","load":"ok","profiles":["acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["0","1"],"shape":["1","1","2"]}]},"inputs":[{"data":["0","1"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000000000000000000001000000000000000100000080000000000000000000000000000000000000001201010000000000010000001c00000040000000000000000400000000000000010000000100000000000000","id":"igdn/acc32_param/67","load":"ok","profiles":["acc64"]} diff --git a/wai/ops-conformance/vectors/l2norm.jsonl b/wai/ops-conformance/vectors/l2norm.jsonl index 0173f0fd4..83ea7e645 100644 --- a/wai/ops-conformance/vectors/l2norm.jsonl +++ b/wai/ops-conformance/vectors/l2norm.jsonl @@ -39,3 +39,4 @@ {"decodes":[{"expect":{"outputs":[{"data":["37632","-37632","-37632","45824","-45824","7288","35894","-43477","32796"],"shape":["3","1","3"]}]},"inputs":[{"data":["16777216","-16777216","-16777216","16777216","-16777216","2668493","12188653","-14763103","11136542"],"shape":["3","1","3"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000004000000040000000000000000000000000000000000000000000000010000000300000080020000000000ffffffffff0000000100000000030000008000000000000000000000000000000000000000190101000000000001000000080000000000004000000000","id":"l2norm/random/38","load":"ok","profiles":["acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-600","-182"],"shape":["1","1","2"]}]},"inputs":[{"data":["-300","-91"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000002000000030000000000000000000000000000000000000000000000010000000100000080020000d4feffffffffffff2c01000000000000010000008000000000000000000000000000000000000000190101000000000001000000080000000000004000000000","id":"l2norm/random/39","load":"ok","profiles":["acc64"]} {"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000fbffffffffffffff0500000000000000010000008000000000000000000000000000000000000000190101000000000001000000080000000100000000000000","id":"l2norm/sizes/40","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["-1","0","0","0"],"shape":["1","2","2"]}]},"inputs":[{"data":["-5","5","1","0"],"shape":["1","2","2"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000002000000020000000000000000000000000000000000000000000000010000000100000080020000fbffffffffffffff050000000000000001000000800000000000000000000000000000000000000019010100000000000100000008000000ffffffffffffffff","id":"l2norm/eps/41","load":"ok","profiles":["acc64"]} diff --git a/wai/ops-conformance/vectors/leaky.jsonl b/wai/ops-conformance/vectors/leaky.jsonl index 91c1cb01b..ebce7cfe9 100644 --- a/wai/ops-conformance/vectors/leaky.jsonl +++ b/wai/ops-conformance/vectors/leaky.jsonl @@ -53,3 +53,4 @@ {"decodes":[{"expect":{"outputs":[{"data":["-1","-1","-1","-1","0","1000"],"shape":["1","1","6"]}]},"inputs":[{"data":["-1000","-7","-5","-1","0","1000"],"shape":["1","1","6"]}],"scalars":[]}],"graph":"5748473101010000020000000100000001000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000000001000000010000008002000018fcffffffffffffe8030000000000000100000080000000000000000000000000000000000000000d01010000000000010000000c00000001000000000000003f000000","id":"leaky/floor/52","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-160","-2","-1","-1","0","1000"],"shape":["1","1","6"]}]},"inputs":[{"data":["-1000","-7","-5","-1","0","1000"],"shape":["1","1","6"]}],"scalars":[]}],"graph":"5748473101010000020000000100000001000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000000001000000010000008002000018fcffffffffffffe8030000000000000100000080000000000000000000000000000000000000000d01010000000000010000000c0000008f020000000000000c000000","id":"leaky/floor/53","load":"ok","profiles":["acc32","acc64"]} {"decodes":[],"graph":"5748473101010000020000000100000001000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000000001000000010000008002000018fcffffffffffffe8030000000000000100000080000000000000000000000000000000000000000d01010000000000010000000c000000010000000000000040000000","id":"leaky/floor/54","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["-1","0","5"],"shape":["1","1","3"]}]},"inputs":[{"data":["-1","0","5"],"shape":["1","1","3"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000ffffffffffffffff05000000000000000100000080000000000000000000000000000000000000000d01010000000000010000000c00000000000080000000001f000000","id":"leaky/acc32_param/55","load":"ok","profiles":["acc64"]} diff --git a/wai/ops-conformance/vectors/lut16.jsonl b/wai/ops-conformance/vectors/lut16.jsonl index aad089cf9..06b60f99c 100644 --- a/wai/ops-conformance/vectors/lut16.jsonl +++ b/wai/ops-conformance/vectors/lut16.jsonl @@ -3,3 +3,5 @@ {"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000005020000f7ffffffffffffff090000000000000001000000800000000000000000000000000000000000000004010100000000000100000004000200048000000000010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100","id":"lut16/exponent/2","load":"model_mismatch","profiles":["acc32","acc64"]} {"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000f7ffffffffffffff090000000000000001000000800000000000000000000000000000000000000004010100000000000100000004000200800200000000010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100","id":"lut16/exponent/3","load":"model_mismatch","profiles":["acc32","acc64"]} {"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000f7ffffffffffffff090000000000000001000000800000000000000000000000000000000000000004010100000000000100000004000200808000000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100","id":"lut16/table/4","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000080ffffffffffff000000000000000001000000800000000000000000000000000000000000000004010100000000000100000004000200808000000000010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100","id":"lut16/step8/5","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000000000000000000008000000000000001000000800000000000000000000000000000000000000004010100000000000100000004000200808000000000010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100","id":"lut16/step8/6","load":"model_mismatch","profiles":["acc32","acc64"]} diff --git a/wai/ops-conformance/vectors/mul.jsonl b/wai/ops-conformance/vectors/mul.jsonl index 4a8f49837..795c70826 100644 --- a/wai/ops-conformance/vectors/mul.jsonl +++ b/wai/ops-conformance/vectors/mul.jsonl @@ -73,3 +73,4 @@ {"decodes":[{"expect":{"outputs":[{"data":["-2147441940","-2147441940"],"shape":["1","1","2"]}]},"inputs":[{"data":["-46340","46340"],"shape":["1","1","2"]},{"data":["46341","-46341"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"574847310101000003000000010000000200010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000100000080020000fc4affffffffffff04b50000000000000100000080020000fb4affffffffffff05b50000000000000100000080000000000000000000000000000000000000001002010000000000010000000200000009000000000000010000000000","id":"mul/edge32/72","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"refuse":"geometry_mismatch"},"inputs":[{"data":["3","3","3","3","3","3","3","3","3","3","3","3"],"shape":["2","2","3"]},{"data":["-3","-3","-3","-3","-3","-3"],"shape":["1","3","2"]}],"scalars":[]}],"graph":"574847310101000003000000010000000200010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000200000080020000fbffffffffffffff05000000000000000100000080020000fbffffffffffffff05000000000000000200000080000000000000000000000000000000000000001002010000000000010000000200000009000000010000010000000001","id":"mul/geometry/73","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-7","-4","-1","2","5","8","-7","-4","-1","2","5","8"],"shape":["2","2","3"]}]},"inputs":[{"data":["3","3","3","3","3","3","3","3","3","3","3","3"],"shape":["2","2","3"]},{"data":["-5","-3","-1","1","3","5"],"shape":["1","2","3"]}],"scalars":[]}],"graph":"574847310101000003000000010000000200010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000200000080020000fbffffffffffffff05000000000000000100000080020000fbffffffffffffff05000000000000000200000080000000000000000000000000000000000000001002010000000000010000000200000009000000010000010000000001","id":"mul/geometry/74","load":"ok","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"57484731010100000300000001000000020001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000010000008002000000000080000000000000008000000000010000008002000000000080000000000000008000000000010000008000000000000000000000000000000000000000100201000000000001000000020000000d00000000000101040000000200000000","id":"mul/step8_q/75","load":"model_mismatch","profiles":["acc32","acc64"]} diff --git a/wai/ops-conformance/vectors/rescale.jsonl b/wai/ops-conformance/vectors/rescale.jsonl index f44a1e96b..a8da07c7c 100644 --- a/wai/ops-conformance/vectors/rescale.jsonl +++ b/wai/ops-conformance/vectors/rescale.jsonl @@ -160,3 +160,8 @@ {"decodes":[{"expect":{"outputs":[{"data":["-2147483647","2147483646","-1","0","12345"],"shape":["1","1","5"]}]},"inputs":[{"data":["-2147483648","2147483647","-1","0","12345"],"shape":["1","1","5"]}],"scalars":[]}],"graph":"5748473101010000020000000100000001000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000000001000000010000008002000000000080ffffffffffffff7f00000000010000008000000000000000000000000000000000000000020101000000000001000000110000000102010104040000ffffff7f1f00000000","id":"rescale/product32/159","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-2147483647","2147483646","-1","0","12345"],"shape":["1","1","5"]}]},"inputs":[{"data":["-2147483648","2147483647","-1","0","12345"],"shape":["1","1","5"]}],"scalars":[]}],"graph":"5748473101010000020000000100000001000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000000001000000010000008002000000000080ffffffffffffff7f00000000010000008000000000000000000000000000000000000000020101000000000001000000110000000202010104040000ffffff7f1f00000000","id":"rescale/product32/160","load":"ok","profiles":["acc32","acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["-1","1","1","3","3","5","5","7"],"shape":["1","1","8"]}]},"inputs":[{"data":["-9","-5","-3","-1","1","3","5","9"],"shape":["1","1","8"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000f7ffffffffffffff09000000000000000100000080000000000000000000000000000000000000000201010000000000010000000d00000002020001000400000103000000","id":"rescale/rounding/161","load":"ok","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000000000000000002000000000000000200100000080000000000000000000000000000000000000000201010000000000010000001100000000020101040400000400000000ffffffff","id":"rescale/step8_q/162","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["9223372036854775803"],"shape":["1","1","1"]}]},"inputs":[{"data":["2305843009213693951"],"shape":["1","1","1"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000ffffffffffffff1fffffffffffffff1f0100000080000000000000000000000000000000000000000201010000000000010000001100000000020101040400000400000000ffffffff","id":"rescale/step8_q/163","load":"ok","profiles":["acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["0","1","2","3"],"shape":["1","1","4"]}]},"inputs":[{"data":["0","1","2","3"],"shape":["1","1","4"]}],"scalars":[]}],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000000000000000000030000000000000001000000800000000000000000000000000000000000000002010100000000000100000011000000000001010800000000000080000000001f","id":"rescale/acc32_param/164","load":"ok","profiles":["acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["0","0"],"shape":["1","1","2"]}]},"inputs":[{"data":["0","3"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000000000000000000030000000000000001000000800000000000000000000000000000000000000002010100000000000100000009000000000000010000000040","id":"rescale/acc32_param/165","load":"ok","profiles":["acc64"]} +{"decodes":[{"expect":{"outputs":[{"data":["0","2147483647"],"shape":["1","1","2"]}]},"inputs":[{"data":["-2147483648","-1"],"shape":["1","1","2"]}],"scalars":[]}],"graph":"5748473101010000020000000100000001000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000000001000000010000008002000000000080ffffffffffffffffffffffff010000008000000000000000000000000000000000000000020101000000000001000000110000000002000100080000000000008000000000","id":"rescale/acc32_param/166","load":"ok","profiles":["acc64"]} diff --git a/wai/ops-conformance/vectors/sigmoid.jsonl b/wai/ops-conformance/vectors/sigmoid.jsonl index b37138a7d..96c2698e8 100644 --- a/wai/ops-conformance/vectors/sigmoid.jsonl +++ b/wai/ops-conformance/vectors/sigmoid.jsonl @@ -29,3 +29,5 @@ {"decodes":[{"expect":{"outputs":[{"data":["0","0","65536","0","65536","0","0","65536","65536","65430","32763","38651","65536","65536","0","65536","65536","65536","0","65536","60015","0","65536","0"],"shape":["2","3","4"]}]},"inputs":[{"data":["-792729","-1048576","826445","-1048576","1048576","-1048576","-1048576","1048576","1048576","421031","0","23772","1048576","1048576","-1048576","1048576","981941","1048576","-1048576","1048576","156422","-1048576","1048576","-1048576"],"shape":["2","3","4"]}],"scalars":[]},{"expect":{"outputs":[{"data":["46483","32763","65529","65536","36","65536","32763","65536","64892","58536","10","0"],"shape":["2","3","2"]}]},"inputs":[{"data":["58597","0","598851","1048576","-489302","1048576","0","1048576","302116","139273","-566856","-788917"],"shape":["2","3","2"]}],"scalars":[]}],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000070000000400000000000000000000000000000000000000000000000100000002000000800200000000f0ffffffffff00001000000000000200000080000000000000000000000000000000000000001b010100000000000100000000000000","id":"sigmoid/random/28","load":"ok","profiles":["acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["32699","32717","32763","32763","32825","32763","32836","32836","32836","32763","32699","32724","32836","32798","32836","32836","32780","32808","32740","32699","32763","32699","32828","32836"],"shape":["3","2","4"]}]},"inputs":[{"data":["-300","-225","0","0","256","-37","300","300","300","0","-300","-197","300","141","300","300","69","183","-130","-300","0","-300","268","300"],"shape":["3","2","4"]}],"scalars":[]}],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000300000080020000d4feffffffffffff2c010000000000000300000080000000000000000000000000000000000000001b010100000000000100000000000000","id":"sigmoid/random/29","load":"ok","profiles":["acc64"]} {"decodes":[{"expect":{"outputs":[{"data":["0","0","0","32771","32763","32764","65536","65536","65536"],"shape":["1","1","9"]}]},"inputs":[{"data":["-9223372036854775807","-2861838","-2816412","-1","0","1","2816412","2861838","9223372036854775807"],"shape":["1","1","9"]}],"scalars":[]}],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000100000000000080ffffffffffffff7f0100000080000000000000000000000000000000000000001b010100000000000100000000000000","id":"sigmoid/edge/30","load":"ok","profiles":["acc64"]} +{"decodes":[],"graph":"57484731010100000200000001000000010001000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000100000080020000000000000000008000000000000000000100000080000000000000000000000000000000000000001b010100000000000100000000000000","id":"sigmoid/step8/31","load":"model_mismatch","profiles":["acc32","acc64"]} +{"decodes":[],"graph":"574847310101000002000000010000000100010000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000001000000800200000000000000000080ffffffffffffff7f0100000080000000000000000000000000000000000000001b010100000000000100000000000000","id":"sigmoid/step8/32","load":"model_mismatch","profiles":["acc32","acc64"]} diff --git a/wai/tools/wai_ops_check.py b/wai/tools/wai_ops_check.py index 39bc82d90..89c3cdc75 100644 --- a/wai/tools/wai_ops_check.py +++ b/wai/tools/wai_ops_check.py @@ -15,15 +15,31 @@ extension's text (and, for the source forms it lowers, integer-payloads), it: lowerings of section 13, and requires each lowered graph's bytes, each set's digest (SPEC 3.1), and that every lowered graph loads; and requires the graph of each graphs/lower_*.jsonl vector to be the role of the set its id names, as - re-lowered. + re-lowered; + - is a certifier (section 1): from each set's lowered graphs it computes the + bounds certificate (the pass of sections 8.1-8.3, the classes and parameter + conditions of section 7, the flags and reasons of section 9.2, and the canonical + writer of section 8.5), and requires the bytes of the committed certificate, + for every set of index.json and the two falsification sets of section 14.3, + each of which must fail the profile it claims. The sets of external.json are + certified too when their files are given (--external NAME=DIR); otherwise their + certificates are checked for what needs no set. -The bounds pass decides the verdict only. It does not write the certificate of -section 8.5, which the certifier half of this checker will. - - python3 -I tools/wai_ops_check.py ops-conformance # check - python3 -I tools/wai_ops_check.py ops-conformance --write DIR # also write the files + python3 -I tools/wai_ops_check.py ops-conformance # check + python3 -I tools/wai_ops_check.py ops-conformance --write DIR # also write the files + python3 -I tools/wai_ops_check.py ops-conformance --external jpegai/v1=DIR ... Exit status 1 on any difference or failure. + + python3 -I tools/wai_ops_check.py certify --capability CAP --lowering ID \\ + [--c N] --member NAME=PATH ... [--profile P] [--out FILE] [--check FILE] + python3 -I tools/wai_ops_check.py certify --whg1 ROLE=PATH ... [--profile P] ... + +certifies one set, or WHG1 graphs on their own, writing the certificate to FILE or +to stdout. Exit status: 0 the verdict meets the profile (acc64 by default); 1 it +does not, and the certificate is still written; 2 a graph is malformed or refused +at load; 3 --check finds a difference, and the first differing path is printed with +both values; 4 the lowering refuses the set; 5 usage. """ import hashlib import json @@ -566,6 +582,16 @@ def load(b): """Load steps 1-8 of section 10.5. Step 8 is the bounds pass and the verdict (section 8): a graph whose verdict meets neither profile is refused, so a graph that loads meets acc64 at least, and g["verdict"] says whether it meets acc32.""" + g = load_graph(b) + if not g["verdict"]["acc64"]: + bad() + return g + + +def load_graph(b): + """Load steps 1-7, then step 8's bounds pass with the refusals the pass makes + (lut16's range, an empty `check` interval), but not the profile against the + verdict: what a certifier needs to write a certificate whatever the verdict.""" g = parse_whg1(b) if g["inputs"][0]["max_h"] == 0: if any(op["name"] in ("gram", "l2norm", "softmax") for op in g["ops"]): @@ -580,9 +606,8 @@ def load(b): hw[i["tensor"]] = (i["max_h"], i["max_w"]) walk(g, hw, None, True) g["sizes"] = hw - g["verdict"] = bounds(g) - if not g["verdict"]["acc64"]: - bad() + g["pass"] = bounds_pass(g) + g["verdict"] = verdict_of([("", g)]) return g @@ -610,10 +635,6 @@ CLASS = { } -def fits_bits(iv, n): - return -(1 << (n - 1)) <= iv[0] and iv[1] <= (1 << (n - 1)) - 1 - - def hull(ivs): return (min(v[0] for v in ivs), max(v[1] for v in ivs)) @@ -907,63 +928,219 @@ def node_bounds(nb, g, op, iv): return [x] -def params32(op): - """The parameter conditions of section 7.2: whether the node meets every one.""" +PROFILES = ("acc32", "acc64") +POLICY = ("derived", "clamp", "check") +_RQ = ["rq.t", "rq.p", "rq.q", "rq.y"] +# Table 8.5-A: the intermediates each operator records, in definition order. Every +# other operator records none. +RECORDS = { + "conv": ["conv.term", "conv.acc"] + _RQ, + "conv_transpose": ["convT.term", "convT.acc"] + _RQ, + "rescale": _RQ, + "chscale": _RQ, + "mul": ["mul.p"] + _RQ, + "gram": ["gram.term", "gram.acc"] + _RQ, + "apply": ["apply.term", "apply.acc"] + _RQ, + "leaky": ["leaky.p"], + "igdn": ["igdn.x2", "igdn.gx2", "igdn.term", "igdn.N", "igdn.r", "igdn.xr"], + "layernorm_c": ["ln.S", "ln.m", "ln.d", "ln.T", "ln.v", "rsq.num", "ln.k", "ln.dk", "ln.n", "ln.ng"], + "l2norm": ["l2.T", "rsq.num", "l2.k", "l2.vk"], + "softmax": ["sm.diff", "exp.negx", "exp.nl", "exp.t2", "exp.c", "sm.sum", "sm.num"], + "sigmoid": ["exp.negx", "exp.nl", "exp.t2", "exp.c", "sig.num"], + "elu": ["exp.negx", "exp.nl", "exp.t2", "exp.c", "elu.p"], +} +# Section 8.5, k_c: the operators that record it, and the term interval of section 6 +# it is taken over. +KC_TERM = {"conv": "conv.term", "conv_transpose": "convT.term", "igdn": "igdn.term", "gram": "gram.term", "apply": "apply.term"} +# Section 8.5, mac: the operators that record it; w_bits for the first three only. +MAC = ("conv", "conv_transpose", "chscale", "mul", "gram", "apply") +# Section 5's table: the operators marked "no" in the wai-ops/1-npu column. +NPU_NO = ("igdn", "layernorm_c", "l2norm", "softmax", "sigmoid", "elu", "gram", "apply") + + +def bits(iv): + """bits([lo, hi]) of section 2: the smallest N >= 1 such that both fit iN.""" + return max((v if v >= 0 else ~v).bit_length() + 1 for v in iv) + + +def acc32_params(op): + """The parameter conditions of section 7.2 the node fails, as their keys, in that + table's order.""" n, P = op["name"], op["p"] f32 = lambda v: I32_MIN <= v <= I32_MAX - ok = True + keys = [] rq = P.get("rq") if rq is not None: - ok = all(map(f32, rq["mult"])) and all(s <= 63 for s in rq["shift"]) and (rq["bias"] != 2 or all(map(f32, rq["biasv"]))) - if n in ("conv", "conv_transpose"): - ok = ok and all(map(f32, P["w"])) - elif n == "chscale": - ok = all(map(f32, P["M"])) and P["shift"] <= 63 - elif n == "igdn": - ok = all(map(f32, P["gamma"])) and P["gf"] <= 63 and P["frac"] <= 63 - elif n == "leaky": - ok = f32(P["a"]) - return ok + if not all(map(f32, rq["mult"])): + keys.append("rq.mult") + if not all(s <= 63 for s in rq["shift"]): + keys.append("rq.shift") + if rq["bias"] == 2 and not all(map(f32, rq["biasv"])): + keys.append("rq.post_bias") + if n in ("conv", "conv_transpose") and not all(map(f32, P["w"])): + keys.append("weights") + if n == "chscale": + if not all(map(f32, P["M"])): + keys.append("chscale.m") + if P["shift"] > 63: + keys.append("chscale.s") + if n == "igdn": + if not all(map(f32, P["gamma"])): + keys.append("igdn.gamma") + if P["gf"] > 63 or P["frac"] > 63: + keys.append("igdn.shift") + if n == "leaky" and not f32(P["a"]): + keys.append("leaky.a") + return keys -def bounds(g): - """The bounds pass (sections 8.1-8.4) and the verdict (section 8.5) of a graph - that passed load steps 1-7: {"acc32": bool, "acc64": bool}. Refuses - (model_mismatch) where the pass itself refuses the graph at load: a `check` - interval that is empty (section 8.1), or lut16's input range (section 5.6).""" +def node_npu(g, op): + """The node's flags of section 9.2, in ascending order, and its reasons of section + 8.5 other than "acc32".""" + n, P = op["name"], op["p"] + flags, reasons = set(), set() + if n == "lut16": + flags.add("lut16") + if n in ("add", "chunk_add"): + state = {i["tensor"] for i in g["inputs"] if i["kind"] == 1} + if any(t in state for t in op["ins"]): + flags.add("state_add") + rq = None + if n == "chscale": + flags.add("chscale") + # A chscale always has a multiplier, M[r][c], and no bias. + rq = (P["round"], True, P["M"], [P["shift"]], False) + elif "rq" in P: + q = P["rq"] + rq = (q["round"], q["m_kind"] != 0, q["mult"], q["shift"], q["bias"] == 2) + if rq is not None: + rnd, has_mult, mults, shifts, post = rq + if rnd == 2: + flags.add("rq_half_even") + if rnd == 0 and has_mult: + flags.add("rq_floor_mult") + if post: + flags.add("rq_post_bias") + if any(m < 0 for m in mults): + flags.add("rq_neg_mult") + if any(not 0 <= s <= 31 for s in shifts): + flags.add("rq_shift_range") + if n in NPU_NO: + reasons.add("op:" + n) + if n == "conv": + cin, G = g["tensors"][op["ins"][0]]["c"], P["groups"] + if (G != 1 and G != cin) or (G == cin and G > 1 and P["cout"] != cin): + reasons.add("conv_groups") + if n == "crop" and any(o[0] == "scalar" for o in P["ops"]): + reasons.add("crop_scalar") + return sorted(flags), reasons + + +def width_failures(nd, p): + """The node's recorded intermediates and producer results (`out.`) that do not + meet profile p's width for their class (section 7.1), as (bits, key).""" + W = WIDTH[p] + f = [(bits(r), k) for k, r in nd["rec"].items() if bits(r) > W[CLASS[k]]] + f += [(bits(o["result"]), "out.%d" % j) for j, o in enumerate(nd["outs"]) if bits(o["result"]) > W["tensor"]] + return f + + +def bounds_pass(g): + """The bounds pass of sections 8.1-8.3 over a graph that passed load steps 1-7, + in graph order. Refuses (model_mismatch) where the pass refuses the graph at + load: a `check` interval that is empty (section 8.1), or lut16's input range + (section 5.6). Returns one record per node: its recorded intermediates, whether + it saturated, its input tensors' intervals, each output's producer result and + interval after its policy, its acc32_params, its npu flags and reasons, and the + profiles it fits (section 8.5).""" T = g["tensors"] - ok = {"acc32": True, "acc64": True} - iv = {} - declared = [(T[i["tensor"]]["lo"], T[i["tensor"]]["hi"]) for i in g["inputs"]] + list(g["scalars"]) - for r in declared: - for p in ok: - ok[p] = ok[p] and fits_bits(r, WIDTH[p]["tensor"]) - for i in g["inputs"]: - iv[i["tensor"]] = (T[i["tensor"]]["lo"], T[i["tensor"]]["hi"]) - for op in g["ops"]: + iv = {i["tensor"]: (T[i["tensor"]]["lo"], T[i["tensor"]]["hi"]) for i in g["inputs"]} + nodes = [] + for k, op in enumerate(g["ops"]): nb = Node() + ins = [iv[t] for t in op["ins"]] results = node_bounds(nb, g, op, iv) - fit = {p: not nb.saturated for p in ok} - for p in ok: - for k, r in nb.rec.items(): - fit[p] = fit[p] and fits_bits(r, WIDTH[p][CLASS[k]]) - for r in results: - fit[p] = fit[p] and fits_bits(r, WIDTH[p]["tensor"]) - fit["acc32"] = fit["acc32"] and params32(op) - for t, (a, b) in zip(op["outs"], results): + if sorted(nb.rec) != sorted(RECORDS.get(op["name"], [])): + raise AssertionError("%s records %s" % (op["name"], sorted(nb.rec))) + outs = [] + for t, r in zip(op["outs"], results): rec = T[t] if rec["policy"] == 0: - iv[t] = (a, b) + ti = r elif rec["policy"] == 1: - iv[t] = (min(max(a, rec["lo"]), rec["hi"]), min(max(b, rec["lo"]), rec["hi"])) + ti = (min(max(r[0], rec["lo"]), rec["hi"]), min(max(r[1], rec["lo"]), rec["hi"])) else: - fit["acc32"] = False - iv[t] = (max(a, rec["lo"]), min(b, rec["hi"])) - if iv[t][0] > iv[t][1]: + ti = (max(r[0], rec["lo"]), min(r[1], rec["hi"])) + if ti[0] > ti[1]: bad() - for p in ok: - ok[p] = ok[p] and fit[p] - return ok + iv[t] = ti + outs.append({"tensor": t, "iv": ti, "result": r, "policy": rec["policy"]}) + flags, reasons = node_npu(g, op) + nd = {"index": k, "op": op, "rec": nb.rec, "saturated": nb.saturated, "ins": ins, "outs": outs, + "acc32_params": acc32_params(op), "flags": flags, "reasons": reasons} + nd["fits"] = {} + for p in PROFILES: + fit = not nd["saturated"] and not width_failures(nd, p) + if p == "acc32": + fit = fit and not nd["acc32_params"] and all(o["policy"] != 2 for o in outs) + nd["fits"][p] = fit + nodes.append(nd) + return nodes + + +def node_failure(nd, p, name): + """The failure of section 8.5 for a node that does not fit profile p.""" + f = {"graph": name, "index": nd["index"], "where": "node"} + if nd["saturated"]: + f["key"] = "saturated" + return f + w = width_failures(nd, p) + if w: + f["bits"], f["key"] = min(w, key=lambda e: (-e[0], e[1].encode())) + else: + f["key"] = nd["acc32_params"][0] if nd["acc32_params"] else "policy.check" + return f + + +def verdict_of(graphs): + """The verdict of section 8.5 over [(name, g)], each g carrying its pass.""" + v = {} + for p in PROFILES: + tw = WIDTH[p]["tensor"] + fail = None + for name, g in graphs: + T = g["tensors"] + for k, i in enumerate(g["inputs"]): + r = (T[i["tensor"]]["lo"], T[i["tensor"]]["hi"]) + if bits(r) > tw: + fail = {"bits": bits(r), "graph": name, "index": k, "key": "range", "where": "input"} + break + if fail is None: + for k, r in enumerate(g["scalars"]): + if bits(r) > tw: + fail = {"bits": bits(r), "graph": name, "index": k, "key": "range", "where": "scalar"} + break + if fail is None: + for nd in g["pass"]: + if not nd["fits"][p]: + fail = node_failure(nd, p, name) + break + if fail is not None: + break + v[p] = fail is None + if fail is not None: + v[p + "_first_failure"] = fail + reasons, flags = set(), set() + if not v["acc32"]: + reasons.add("acc32") + for _, g in graphs: + for nd in g["pass"]: + reasons |= nd["reasons"] + flags |= set(nd["flags"]) + v["npu_reasons"] = sorted(reasons, key=lambda s: s.encode()) + v["npu"] = not reasons + v["npu_flags"] = sorted(flags, key=lambda s: s.encode()) + return v # --------------------------------------------------------------- the operators (section 5) @@ -1262,8 +1439,8 @@ def run(g, data_inputs, scalars, state): for op in g["ops"]: outs = ev(g, op, vals, hw, scalars) for t, ten in zip(op["outs"], outs): - # A value outside i64 is one load step 8 excludes; before the certifier - # exists, such a decode is refused. + # A value outside i64 is one load step 8 excludes; should one be formed + # all the same, the decode is refused rather than carried on. if any(v is None or not I64_MIN <= v <= I64_MAX for v in ten.d): raise Refuse("model_mismatch") if not apply_policy(g["tensors"][t], ten): @@ -1347,6 +1524,136 @@ def graph_line(v): return out +# --------------------------------------------------------------- the certificate (8.5) + + +def ivj(iv): + return {"bits": bits(iv), "hi": iv[1], "lo": iv[0]} + + +def node_json(nd): + op = nd["op"] + n, P = op["name"], op["p"] + d = { + "acc32_params": nd["acc32_params"], + "fits": [p for p in PROFILES if nd["fits"][p]], + "index": nd["index"], + "intermediates": {k: ivj(nd["rec"][k]) for k in RECORDS.get(n, [])}, + "npu_flags": nd["flags"], + "op": n, + "out": [{"bits": bits(o["iv"]), "hi": o["iv"][1], "lo": o["iv"][0], "policy": POLICY[o["policy"]], + "result": ivj(o["result"]), "tensor": o["tensor"]} for o in nd["outs"]], + "saturated": nd["saturated"], + } + if n in KC_TERM: + t = nd["rec"][KC_TERM[n]] + m = max(abs(t[0]), abs(t[1])) + d["k_c"] = "unbounded" if m == 0 else I32_MAX // m + if n in MAC: + d["mac"] = {"a_bits": [bits(x) for x in nd["ins"]]} + if n in ("conv", "conv_transpose", "chscale"): + w = P["M"] if n == "chscale" else P["w"] + d["mac"]["w_bits"] = bits((min(w), max(w))) + return d + + +def graph_json(name, b, g): + T = g["tensors"] + inputs = [] + for i in g["inputs"]: + rec = T[i["tensor"]] + e = {"hi": rec["hi"], "kind": "state" if i["kind"] else "data", "lo": rec["lo"], "max_h": i["max_h"], + "max_w": i["max_w"], "policy": POLICY[rec["policy"]], "tensor": i["tensor"]} + if i["kind"]: + e["init"], e["src"] = i["init"], i["src"] + inputs.append(e) + return { + "graph_sha256": hashlib.sha256(b).hexdigest(), + "inputs": inputs, + "name": name, + "nodes": [node_json(nd) for nd in g["pass"]], + "scalars": [{"hi": hi, "index": k, "lo": lo} for k, (lo, hi) in enumerate(g["scalars"])], + } + + +def canonical(v): + """The canonical JSON of section 8.5, as bytes. Every string is printable ASCII; + a role or capability name outside that alphabet cannot be certified.""" + def strings(x): + if isinstance(x, str): + yield x + elif isinstance(x, list): + for y in x: + yield from strings(y) + elif isinstance(x, dict): + for k, y in x.items(): + yield k + yield from strings(y) + for s in strings(v): + if any(not 0x20 <= ord(ch) <= 0x7E for ch in s): + raise ValueError("a string outside printable ASCII cannot be certified: %r" % s) + return cw(v).encode("ascii") + + +def certificate(capability, lowering, set_sha256, roles): + """The bounds certificate of section 8.5 for the graphs [(role, WHG1 bytes)], in + the order given: (its canonical bytes, its verdict). Each graph passes load steps + 1-7 and the bounds pass, or the Refuse of the step that fails propagates.""" + gs = [(name, b, load_graph(b)) for name, b in roles] + v = verdict_of([(name, g) for name, _, g in gs]) + cert = { + "capability": capability, + "certificate": "wai-ops/1 bounds", + "graphs": [graph_json(name, b, g) for name, b, g in gs], + "lowering": lowering, + "set_sha256": set_sha256, + "verdict": v, + } + return canonical(cert), v + + +ABSENT = "(absent)" + + +def json_diffs(a, b, path="", out=None, limit=None): + """The JSON paths at which two parsed values differ, in document order, each + with both values: [(path, a's value, b's value)].""" + out = [] if out is None else out + if limit is not None and len(out) >= limit: + return out + if isinstance(a, dict) and isinstance(b, dict): + for k in sorted(set(a) | set(b), key=lambda s: s.encode()): + p = path + ("." + k if k.isidentifier() else '["%s"]' % k) + if k not in a or k not in b: + out.append((p, a.get(k, ABSENT), b.get(k, ABSENT))) + else: + json_diffs(a[k], b[k], p, out, limit) + elif isinstance(a, list) and isinstance(b, list): + for k in range(max(len(a), len(b))): + p = "%s[%d]" % (path, k) + if k >= len(a) or k >= len(b): + out.append((p, a[k] if k < len(a) else ABSENT, b[k] if k < len(b) else ABSENT)) + else: + json_diffs(a[k], b[k], p, out, limit) + elif a != b: + out.append((path or "$", a, b)) + return out[:limit] if limit is not None else out + + +def first_difference(got, want): + """Part of what a `--check` mismatch prints: the first differing JSON path, with + both values.""" + try: + a, b = json.loads(got), json.loads(want) + except ValueError: + return "the committed file is not JSON" + d = json_diffs(a, b, limit=1) + if not d: + return "the same JSON, written differently" + p, x, y = d[0] + return "first difference at %s: computed %s, committed %s" % (p, cw(x) if x is not ABSENT else x, cw(y) if y is not ABSENT else y) + + # --------------------------------------------------------------- stage operators (5E) @@ -2231,30 +2538,44 @@ def jpegai_lower(norm_b, hy_b, huv_b): def lower_set(entry, files): + """The set's lowered graphs, [(role, WHG1 bytes)] in section 13.0's role order. + Raises LowerRefuse when the lowering refuses the set.""" low, cap = entry["lowering"], entry["capability"] - try: - if low == "int_synth/1": - roles = int_synth_lower(files["int_synth.json"]) - elif low == "whm1/1" and cap == "wai.splat.int_codec": - roles = [("g_s", whm1_lower(files["g_s.whm"], True))] - elif low == "whm1/1": - roles = [("h_s", whm1_lower(files["h_s.whm"], False)), ("g_s", whm1_lower(files["g_s.whm"], True))] - elif low == "wam1/1": - roles = [("g_s", wam1_lower(files["model.wam"]))] - elif low == "wmb1/1": - roles = wmb1_lower(files["model.wmb"]) - elif low == "world/1": - roles = world_lower(files["T.whm"], files["g_s.whm"], dec(entry["c"])) - elif low == "jpegai-int/1": - roles = jpegai_lower(files["norm.json"], files["weights/hs_y.json"], files["weights/hs_uv.json"]) - else: - raise ValueError("no lowering %r" % low) - except LowerRefuse: - raise ValueError("the lowering refused the set") - # Every lowered graph loads. - for _, b in roles: - load(b) - return roles + if low == "int_synth/1": + return int_synth_lower(files["int_synth.json"]) + if low == "whm1/1" and cap == "wai.splat.int_codec": + return [("g_s", whm1_lower(files["g_s.whm"], True))] + if low == "whm1/1": + return [("h_s", whm1_lower(files["h_s.whm"], False)), ("g_s", whm1_lower(files["g_s.whm"], True))] + if low == "wam1/1": + return [("g_s", wam1_lower(files["model.wam"]))] + if low == "wmb1/1": + return wmb1_lower(files["model.wmb"]) + if low == "world/1": + return world_lower(files["T.whm"], files["g_s.whm"], dec(entry["c"])) + if low == "jpegai-int/1": + return jpegai_lower(files["norm.json"], files["weights/hs_y.json"], files["weights/hs_uv.json"]) + raise ValueError("no lowering %r" % low) + + +def cert_path(root, entry): + """Section 14.3: certificates//.json.""" + return os.path.join(root, "certificates", entry["capability"], entry["set_sha256"] + ".json") + + +def check_set_certificate(root, entry, roles, write): + """Recomputes a set's certificate from its lowered graphs and requires the bytes + of the committed one. Returns the verdict.""" + got, v = certificate(entry["capability"], entry["lowering"], entry["set_sha256"], roles) + path = cert_path(root, entry) + if write: + p = os.path.join(write, os.path.relpath(path, root)) + os.makedirs(os.path.dirname(p), exist_ok=True) + open(p, "wb").write(got) + want = open(path, "rb").read() + if got != want: + raise ValueError("the certificate differs: %s" % first_difference(got, want)) + return v def set_digest(files): @@ -2267,7 +2588,7 @@ def set_digest(files): # --------------------------------------------------------------- main -def check(root, write): +def check(root, write, external=None): wai = os.path.dirname(os.path.abspath(root)) failures = 0 nfiles = nvec = 0 @@ -2297,15 +2618,24 @@ def check(root, write): k = next((k for k in range(min(len(a), len(b))) if a[k] != b[k]), min(len(a), len(b))) print("DIFF %s/%s: line %d differs" % (sub, name, k + 1)) print("rewrote %d vector files, %d vectors" % (nfiles, nvec)) - idx = json.load(open(os.path.join(root, "certificates", "index.json"))) - nsets = ngraphs = 0 + nsets = ngraphs = ncerts = 0 lowered = {} - for e in idx["sets"]: + # The sets index.json lists, then the falsification sets of section 14.3. Each is + # re-lowered, its lowered graphs compared, and its certificate recomputed from + # them and compared. An index set's graphs each load (steps 1-8), so its verdict + # meets acc64; a falsification set's verdict fails the profile it claims. + listed = [(e, None) for e in json.load(open(os.path.join(root, "certificates", "index.json")))["sets"]] + listed += [(e, e["claim"]) for e in json.load(open(os.path.join(root, "certificates", "falsification.json")))["sets"]] + for e, claim in listed: + what = "falsification set" if claim else "set" try: files = {m: open(os.path.join(wai, p), "rb").read() for m, p in e["members"].items()} if set_digest(files) != e["set_sha256"]: raise ValueError("the set's digest differs") - roles = lower_set(e, files) + try: + roles = lower_set(e, files) + except LowerRefuse: + raise ValueError("the lowering refused the set") if len(roles) != len(e["roles"]): raise ValueError("the roles differ") for (role, b), path in zip(roles, e["roles"]): @@ -2317,15 +2647,66 @@ def check(root, write): open(p, "wb").write(b) if open(os.path.join(wai, path), "rb").read() != b: raise ValueError("%s: the lowered graph differs" % role) - if e.get("synthetic"): + if e.get("synthetic") and not claim: lowered[(FORM_FILE[e["lowering"]], e["name"], role)] = b ngraphs += 1 nsets += 1 + v = check_set_certificate(root, e, roles, write) + ncerts += 1 + if claim is None and not v["acc64"]: + raise ValueError("a lowered graph does not load: the verdict fails acc64") + if claim is not None and v[claim]: + raise ValueError("its verdict meets %s, the profile it must fail" % claim) + except Refuse as ex: + failures += 1 + print("FAIL %s %s (%s): a lowered graph is refused at load: %s" % (what, e.get("name"), e.get("capability"), ex.code)) except Exception as ex: failures += 1 - print("FAIL lowering %s (%s): %s" % (e.get("name"), e.get("capability"), ex)) - print("re-lowered %d sets, %d graphs" % (nsets, ngraphs)) + print("FAIL %s %s (%s): %s" % (what, e.get("name"), e.get("capability"), ex)) + print("re-lowered %d sets, %d graphs; recomputed %d certificates byte for byte" % (nsets, ngraphs, ncerts)) failures += check_lower_vectors(root, lowered) + failures += check_external(root, external or {}, write) + return failures + + +def check_external(root, external, write): + """The sets of external.json, whose certificates are committed although the sets + are not. With the set's files (`external` maps an entry's name to the directory + that holds them), the certificate is recomputed and compared. Without them, only + what needs no set: the certificate is canonical, names its set, its capability + and its lowering, and its verdict meets the profile the entry gives.""" + failures = n_full = n_part = 0 + for e in json.load(open(os.path.join(root, "certificates", "external.json")))["sets"]: + try: + want = open(cert_path(root, e), "rb").read() + d = e["name"] in external + if d: + files = {m: open(os.path.join(external[e["name"]], f), "rb").read() for m, f in e["members"].items()} + if set_digest(files) != e["set_sha256"]: + raise ValueError("the set's digest differs") + try: + roles = lower_set(e, files) + except LowerRefuse: + raise ValueError("the lowering refused the set") + check_set_certificate(root, e, roles, write) + c = json.loads(want) + if canonical(c) != want: + raise ValueError("the certificate is not canonical") + if (c["set_sha256"], c["capability"], c["lowering"]) != (e["set_sha256"], e["capability"], e["lowering"]): + raise ValueError("the certificate names another set") + if c["verdict"][e["profile"]] is not True: + raise ValueError("its verdict does not meet %s" % e["profile"]) + if d: + n_full += 1 + else: + n_part += 1 + except Refuse as ex: + failures += 1 + print("FAIL external set %s: a lowered graph is refused at load: %s" % (e["name"], ex.code)) + except Exception as ex: + failures += 1 + print("FAIL external set %s: %s" % (e["name"], ex)) + print("external sets: %d certificates recomputed byte for byte, %d checked without their set" % (n_full, n_part)) return failures @@ -2364,16 +2745,99 @@ def check_lower_vectors(root, lowered): return failures +def certify_main(args): + """`certify`: one set, or WHG1 graphs on their own, to a certificate (section 8.5), + with the exit status of the bounds tool: 0 the verdict meets the profile; 1 it + does not (the certificate is still written); 2 a graph is malformed or refused at + load; 3 `--check` finds a difference; 4 the lowering refuses the set; 5 usage.""" + opts = {"--capability": None, "--lowering": None, "--c": None, "--profile": "acc64", "--out": None, "--check": None} + members, graphs = [], [] + k = 0 + while k < len(args): + a = args[k] + if k + 1 >= len(args) or (a not in opts and a not in ("--member", "--whg1")): + print(CERTIFY_USAGE, file=sys.stderr) + return 5 + v = args[k + 1] + if a in ("--member", "--whg1"): + if "=" not in v: + print(CERTIFY_USAGE, file=sys.stderr) + return 5 + (members if a == "--member" else graphs).append(tuple(v.split("=", 1))) + else: + opts[a] = v + k += 2 + if bool(members) == bool(graphs) or opts["--profile"] not in PROFILES or (members and not (opts["--capability"] and opts["--lowering"])): + print(CERTIFY_USAGE, file=sys.stderr) + return 5 + try: + if graphs: + roles = [(name, open(path, "rb").read()) for name, path in graphs] + capability, lowering, digest = opts["--capability"], "whg1", None + else: + files = {name: open(path, "rb").read() for name, path in members} + capability, lowering, digest = opts["--capability"], opts["--lowering"], set_digest(files) + entry = {"capability": capability, "lowering": lowering, "c": opts["--c"], "set_sha256": digest} + try: + roles = lower_set(entry, files) + except (LowerRefuse, KeyError, ValueError) as ex: + print("the lowering refused the set%s" % (": %s" % ex if str(ex) else ""), file=sys.stderr) + return 4 + except OSError as ex: + print(ex, file=sys.stderr) + return 5 + try: + got, v = certificate(capability, lowering, digest, roles) + except Refuse as ex: + print("a graph is refused at load: %s" % ex.code, file=sys.stderr) + return 2 + if opts["--out"]: + open(opts["--out"], "wb").write(got) + else: + sys.stdout.write(got.decode("ascii")) + sys.stdout.flush() + p = opts["--profile"] + if opts["--check"]: + want = open(opts["--check"], "rb").read() + if got != want: + print("--check: %s" % first_difference(got, want), file=sys.stderr) + return 3 + if not v[p]: + print("the verdict does not meet %s: %s" % (p, cw(v[p + "_first_failure"])), file=sys.stderr) + return 1 + print("the verdict meets %s: %s" % (p, cw(v)), file=sys.stderr) + return 0 + + +CERTIFY_USAGE = """usage: + wai_ops_check.py certify --capability CAP --lowering ID [--c N] --member NAME=PATH ... + [--profile acc32|acc64] [--out FILE] [--check FILE] + wai_ops_check.py certify --whg1 ROLE=PATH ... [--capability CAP] + [--profile acc32|acc64] [--out FILE] [--check FILE]""" + + def main(argv): - if len(argv) not in (2, 4) or (len(argv) == 4 and argv[2] != "--write"): + if len(argv) >= 2 and argv[1] == "certify": + return certify_main(argv[2:]) + if len(argv) < 2 or len(argv) % 2: print(__doc__) return 2 - write = argv[3] if len(argv) == 4 else None - failures = check(argv[1], write) + write, external = None, {} + for k in range(2, len(argv), 2): + a, v = argv[k], argv[k + 1] + if a == "--write": + write = v + elif a == "--external" and "=" in v: + name, d = v.split("=", 1) + external[name] = d + else: + print(__doc__) + return 2 + failures = check(argv[1], write, external) if failures: print("%d failures" % failures) return 1 - print("ops-conformance: every vector file and every lowered graph rewritten byte for byte") + print("ops-conformance: every vector file, every lowered graph and every certificate rewritten byte for byte") return 0 diff --git a/wai/wai-ops/Cargo.toml b/wai/wai-ops/Cargo.toml index 2df213ad8..a96d72394 100644 --- a/wai/wai-ops/Cargo.toml +++ b/wai/wai-ops/Cargo.toml @@ -1,8 +1,8 @@ # The reference implementation of `wai-ops/1`, the integer operator set # (`extensions/integer-operators.md`): the `WHG1` graph form, the load and run-time # plans, the interpreter, the stage operators, the canonical lowerings of the -# registered integer network forms, and the conformance vectors of -# `../ops-conformance/`. +# registered integer network forms, the bounds pass with its certificate (load step +# 8), and the conformance vectors of `../ops-conformance/`. # # `no_std` with `alloc`, and no dependencies, so that a model checker can include # its sources by `#[path]` the way `wai-verify` includes the other integer sources. @@ -13,28 +13,14 @@ edition = "2024" rust-version = "1.97" license = "Apache-2.0" publish = false -description = "WAI integer operator set wai-ops/1: WHG1 graphs, plans, interpreter, stage operators, lowerings and conformance vectors" +description = "WAI integer operator set wai-ops/1: WHG1 graphs, plans, interpreter, stage operators, lowerings, bounds certificates and conformance vectors" [lib] name = "wai_ops" path = "src/lib.rs" -# The vector and lowering tool. It reads and writes files, so it is `std`; the -# library it drives is not. -[[bin]] -name = "wai-ops" -path = "src/bin/wai-ops.rs" -required-features = ["uncertified"] - -[features] -# Load step 8 (the bounds pass and the profile verdict, §10.5) is not built yet. -# Without this switch a graph cannot complete its load, and since the interpreter -# runs only a graph `graph::load` returned, the default build decodes nothing; with -# it, step 8 is skipped, so the vectors and the lowerings run before the certifier -# exists. The tests, the conformance tool and its browser-engine build (`node/`) -# enable it, and no decoder may. wai-ops is a workspace of its own, so no other -# crate's features unify with it. The switch goes when the certifier lands. -uncertified = [] +# The tool that drives this library (the certifier, the lowerings and the corpus) is +# `wai-verify`, a binary of `../wai-verify` behind its `cli` feature. [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(kani)"] } diff --git a/wai/wai-ops/node/Cargo.toml b/wai/wai-ops/node/Cargo.toml index 919fbfa45..f2a2366a7 100644 --- a/wai/wai-ops/node/Cargo.toml +++ b/wai/wai-ops/node/Cargo.toml @@ -14,7 +14,7 @@ crate-type = ["cdylib"] path = "src/lib.rs" [dependencies] -wai-ops = { path = "..", features = ["uncertified"] } +wai-ops = { path = ".." } [profile.release] debug = false diff --git a/wai/wai-ops/src/bin/wai-ops.rs b/wai/wai-ops/src/bin/wai-ops.rs deleted file mode 100644 index 66d00f4c5..000000000 --- a/wai/wai-ops/src/bin/wai-ops.rs +++ /dev/null @@ -1,225 +0,0 @@ -//! `wai-ops`: the vector and lowering tool of `wai/ops-conformance/`. -//! -//! ```text -//! wai-ops vectors gen write every file of /ops-conformance -//! wai-ops vectors verify recompute every vector file and every lowered -//! graph, and regenerate the corpus; every byte -//! must equal the committed one -//! wai-ops vectors recompute recompute one vector file to stdout -//! ``` -//! -//! Exit status: 0 when everything verifies, 1 on a difference, 2 on a usage or I/O -//! error. - -use std::path::{Path, PathBuf}; -use std::process::ExitCode; - -use wai_ops::generate; -use wai_ops::json; -use wai_ops::vectors::{self, Kind}; - -fn usage() -> ExitCode { - eprintln!("usage: wai-ops vectors gen|verify | wai-ops vectors recompute "); - ExitCode::from(2) -} - -fn kind_of(rel: &str) -> Option { - if !rel.ends_with(".jsonl") { - return None; - } - if rel.starts_with("stage/") { Some(Kind::Stage) } else { Some(Kind::Graph) } -} - -fn reader(wai: &Path) -> impl Fn(&str) -> Option> + '_ { - move |p: &str| std::fs::read(wai.join(p)).ok() -} - -fn write_corpus(wai: &Path) -> ExitCode { - let read = reader(wai); - let (files, dropped) = match generate::all(&read) { - Ok(x) => x, - Err(e) => { - eprintln!("gen: {e}"); - return ExitCode::from(2); - } - }; - let root = wai.join("ops-conformance"); - for (rel, bytes) in &files { - let p = root.join(rel); - if let Some(d) = p.parent() { - std::fs::create_dir_all(d).expect("create directory"); - } - std::fs::write(&p, bytes).expect("write"); - } - let lines: usize = files.iter().filter(|(r, _)| r.ends_with(".jsonl")).map(|(_, b)| b.iter().filter(|&&c| c == b'\n').count()).sum(); - eprintln!("wrote {} files, {} vectors", files.len(), lines); - for (f, d) in dropped.iter().filter(|(_, d)| *d > 0) { - eprintln!(" {f}: {d} cases met no profile and were not written"); - } - ExitCode::SUCCESS -} - -fn list(dir: &Path, base: &Path, out: &mut Vec) { - let Ok(rd) = std::fs::read_dir(dir) else { return }; - let mut v: Vec = rd.filter_map(|e| e.ok().map(|e| e.path())).collect(); - v.sort(); - for p in v { - if p.is_dir() { - list(&p, base, out); - } else { - out.push(p.strip_prefix(base).expect("below base").to_path_buf()); - } - } -} - -fn verify(wai: &Path) -> ExitCode { - let root = wai.join("ops-conformance"); - let mut bad = 0usize; - // 1. Every committed vector file, recomputed from its inputs. - let mut committed = Vec::new(); - list(&root, &root, &mut committed); - let (mut nfiles, mut nlines) = (0usize, 0usize); - for rel in &committed { - let r = rel.to_string_lossy().replace('\\', "/"); - let Some(kind) = kind_of(&r) else { continue }; - let text = std::fs::read_to_string(root.join(rel)).expect("read"); - nfiles += 1; - nlines += text.lines().count(); - match vectors::recompute_file(kind, &text) { - Ok(out) if out == text => {} - Ok(out) => { - bad += 1; - let n = out.lines().zip(text.lines()).position(|(a, b)| a != b).map_or(out.lines().count().min(text.lines().count()), |n| n); - eprintln!("DIFF {r}: line {} differs when recomputed", n + 1); - } - Err(e) => { - bad += 1; - eprintln!("FAIL {r}: {e}"); - } - } - } - eprintln!("recomputed {nfiles} vector files, {nlines} vectors"); - // 2. Every lowered graph, from its set, as the index lists it. - match std::fs::read(root.join("certificates/index.json")) { - Ok(b) => match json::parse(&b) { - Ok(idx) => { - let read = reader(wai); - let mut n = 0; - for s in idx.get("sets").and_then(|v| v.as_arr()).unwrap_or(&[]) { - n += 1; - if let Err(e) = check_set(s, &read, wai) { - bad += 1; - eprintln!("FAIL lowering {}: {e}", s.get("name").and_then(|v| v.as_str()).unwrap_or("?")); - } - } - eprintln!("re-lowered {n} sets"); - } - Err(_) => { - bad += 1; - eprintln!("FAIL certificates/index.json does not parse"); - } - }, - Err(e) => { - bad += 1; - eprintln!("FAIL certificates/index.json: {e}"); - } - } - // 3. The generator writes the committed corpus again, byte for byte, and nothing - // is committed that it does not write (the README aside). - let read = reader(wai); - match generate::all(&read) { - Ok((files, _)) => { - let mut want: Vec = Vec::new(); - for (rel, bytes) in &files { - want.push(rel.clone()); - match std::fs::read(root.join(rel)) { - Ok(c) if &c == bytes => {} - Ok(_) => { - bad += 1; - eprintln!("DIFF {rel}: the generator writes other bytes"); - } - Err(_) => { - bad += 1; - eprintln!("MISSING {rel}"); - } - } - } - for rel in &committed { - let r = rel.to_string_lossy().replace('\\', "/"); - if r != "README.md" && r != ".gitattributes" && !want.contains(&r) { - bad += 1; - eprintln!("EXTRA {r}: committed, but the generator does not write it"); - } - } - eprintln!("regenerated {} files", files.len()); - } - Err(e) => { - bad += 1; - eprintln!("FAIL gen: {e}"); - } - } - if bad == 0 { - eprintln!("ops-conformance: every file verifies"); - ExitCode::SUCCESS - } else { - eprintln!("ops-conformance: {bad} failures"); - ExitCode::from(1) - } -} - -fn check_set(s: &json::Value, read: &dyn Fn(&str) -> Option>, wai: &Path) -> Result<(), String> { - use wai_ops::generate::sets; - let name = s.get("name").and_then(|v| v.as_str()).ok_or("name")?; - let cap = s.get("capability").and_then(|v| v.as_str()).ok_or("capability")?; - let lowering = s.get("lowering").and_then(|v| v.as_str()).ok_or("lowering")?; - let c = s.get("c").and_then(|v| v.as_dec()).and_then(|v| v.to_i64()).map(|v| v as u32); - let members: Vec<(String, String)> = s.get("members").and_then(|v| v.as_obj()).ok_or("members")? - .iter().map(|(k, v)| (k.clone(), v.as_str().unwrap_or("").to_string())).collect(); - let mut bytes = Vec::new(); - for (k, p) in &members { - bytes.push((k.clone(), read(p).ok_or_else(|| format!("cannot read {p}"))?)); - } - let m: Vec<(&str, Vec)> = bytes.iter().map(|(k, b)| (k.as_str(), b.clone())).collect(); - let digest = sets::set_digest(&m); - if Some(digest.as_str()) != s.get("set_sha256").and_then(|v| v.as_str()) { - return Err(format!("set digest {digest} differs")); - } - let leak = |x: &str| -> &'static str { Box::leak(x.to_string().into_boxed_str()) }; - let set = sets::Set { name: leak(name), capability: leak(cap), lowering: leak(lowering), members: vec![], c, note: "" }; - let l = sets::lower_set(&set, &m)?; - let paths: Vec<&str> = s.get("roles").and_then(|v| v.as_arr()).ok_or("roles")?.iter().filter_map(|v| v.as_str()).collect(); - if paths.len() != l.roles.len() { - return Err("the roles differ".into()); - } - for ((role, g), p) in l.roles.iter().zip(paths) { - let want = std::fs::read(wai.join(p)).map_err(|e| format!("{p}: {e}"))?; - if want != g.to_bytes() { - return Err(format!("{role}: the lowered graph differs from {p}")); - } - } - Ok(()) -} - -fn main() -> ExitCode { - let a: Vec = std::env::args().collect(); - match a.iter().map(String::as_str).collect::>().as_slice() { - [_, "vectors", "gen", dir] => write_corpus(Path::new(dir)), - [_, "vectors", "verify", dir] => verify(Path::new(dir)), - [_, "vectors", "recompute", file] => { - let p = Path::new(file); - let rel = p.to_string_lossy(); - let kind = if rel.contains("/stage/") || rel.starts_with("stage/") { Kind::Stage } else { Kind::Graph }; - match std::fs::read_to_string(p).map_err(|e| e.to_string()).and_then(|t| vectors::recompute_file(kind, &t)) { - Ok(out) => { - print!("{out}"); - ExitCode::SUCCESS - } - Err(e) => { - eprintln!("{e}"); - ExitCode::from(2) - } - } - } - _ => usage(), - } -} diff --git a/wai/wai-ops/src/bounds.rs b/wai/wai-ops/src/bounds.rs new file mode 100644 index 000000000..010e7a2c2 --- /dev/null +++ b/wai/wai-ops/src/bounds.rs @@ -0,0 +1,1665 @@ +//! Load step 8 (§10.5): the bounds pass (§8.1–§8.3), each node's classes and +//! parameter conditions (§7), the verdict and the bounds certificate (§8.5), and +//! admissible ranges (§8.4). +//! +//! Every interval end is an [`I512`], and every primitive operation the pass performs +//! goes through [`Ar`], which saturates its result at `±2^255` and marks the node +//! when that changed a value (§8.1). A sum a rule writes with `Σ` is a left fold in +//! the order its index runs; a partial-sum interval adds terms of one sign only, so +//! its order does not matter. The pass never reads a payload: its result is a +//! function of the graph's bytes, the sizes the load plan gives, and nothing else. + +use alloc::format; +use alloc::string::{String, ToString}; +use alloc::vec; +use alloc::vec::Vec; + +use crate::code::{Code, Refusal, Site}; +use crate::graph::{BiasKind, Graph, Op, Operand, Params, Policy, Round, Rq, op_name, opcode::*}; +use crate::json::{self, C}; +use crate::sha256::sha256; +use crate::xint::I512; + +// ------------------------------------------------------------------ profiles + +/// An accumulator profile (§7.2). +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Profile { + Acc32, + Acc64, +} + +impl Profile { + /// Both profiles, in the ascending order the certificate writes them. + pub const ALL: [Profile; 2] = [Profile::Acc32, Profile::Acc64]; + + pub fn as_str(self) -> &'static str { + match self { + Profile::Acc32 => "acc32", + Profile::Acc64 => "acc64", + } + } + + pub fn parse(s: &str) -> Option { + match s { + "acc32" => Some(Profile::Acc32), + "acc64" => Some(Profile::Acc64), + _ => None, + } + } +} + +/// A width class (§7.1). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Class { + Tensor, + Acc, + Wide, + Product, +} + +impl Class { + /// The width, in bits, a value of this class fits under `p` (§7.1). + pub fn width(self, p: Profile) -> u32 { + match (self, p) { + (Class::Tensor | Class::Acc, Profile::Acc64) => 64, + (Class::Wide | Class::Product, Profile::Acc64) => 128, + (Class::Tensor | Class::Acc | Class::Wide, Profile::Acc32) => 32, + (Class::Product, Profile::Acc32) => 64, + } + } +} + +// ------------------------------------------------------------------ intervals + +/// An integer interval `[lo, hi]`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Iv { + pub lo: I512, + pub hi: I512, +} + +impl Iv { + pub fn new(lo: I512, hi: I512) -> Iv { + Iv { lo, hi } + } + pub fn point(v: I512) -> Iv { + Iv { lo: v, hi: v } + } + pub fn of_i64(lo: i64, hi: i64) -> Iv { + Iv { lo: I512::from_i64(lo), hi: I512::from_i64(hi) } + } + /// The smallest interval that holds both. + pub fn hull(self, o: Iv) -> Iv { + Iv { lo: self.lo.min(o.lo), hi: self.hi.max(o.hi) } + } + /// `bits([lo, hi])` (§2). + pub fn bits(&self) -> u32 { + I512::bits(self.lo, self.hi) + } + /// Whether both ends fit iN. + pub fn fits(&self, n: u32) -> bool { + self.bits() <= n + } + /// Whether `o` lies within this interval. + pub fn holds(&self, o: &Iv) -> bool { + self.lo <= o.lo && o.hi <= self.hi + } +} + +fn hull_opt(a: Option, b: Iv) -> Option { + Some(match a { + None => b, + Some(a) => a.hull(b), + }) +} + +const Z: I512 = I512::ZERO; + +fn i(v: i64) -> I512 { + I512::from_i64(v) +} +fn u(v: u64) -> I512 { + I512::from_u64(v) +} + +/// The arithmetic of the pass (§8.1): every primitive result is saturated at +/// `±2^255`, and `hit` records whether that changed a value. +#[derive(Default)] +struct Ar { + hit: bool, +} + +impl Ar { + fn s(&mut self, v: I512) -> I512 { + let (r, changed) = v.sat(); + self.hit |= changed; + r + } + fn add(&mut self, a: I512, b: I512) -> I512 { + self.s(a.add(b)) + } + fn sub(&mut self, a: I512, b: I512) -> I512 { + self.s(a.sub(b)) + } + fn mul(&mut self, a: I512, b: I512) -> I512 { + self.s(a.mul(b)) + } + fn neg(&mut self, a: I512) -> I512 { + self.s(a.neg()) + } + fn abs(&mut self, a: I512) -> I512 { + self.s(a.abs()) + } + fn min(&mut self, a: I512, b: I512) -> I512 { + self.s(a.min(b)) + } + fn max(&mut self, a: I512, b: I512) -> I512 { + self.s(a.max(b)) + } + /// `⌊a / b⌋`, `b > 0`. + fn fdiv(&mut self, a: I512, b: I512) -> I512 { + self.s(a.div_floor(b)) + } + /// `⌊a / 2^k⌋`. + fn shr(&mut self, a: I512, k: u32) -> I512 { + self.s(a.shr_floor(k)) + } + fn isqrt(&mut self, a: I512) -> I512 { + self.s(a.isqrt()) + } + fn isqrt_ceil(&mut self, a: I512) -> I512 { + self.s(a.isqrt_ceil()) + } + fn clamp(&mut self, v: I512, lo: I512, hi: I512) -> I512 { + let m = self.max(v, lo); + self.min(m, hi) + } + + /// The term interval of a weight `w` over `[l, h]` (§8.2). + fn term(&mut self, w: I512, x: Iv) -> Iv { + let (a, b) = (self.mul(w, x.lo), self.mul(w, x.hi)); + Iv::new(a.min(b), a.max(b)) + } + /// The corner hull of two run-time intervals (§8.2). + fn corner(&mut self, a: Iv, b: Iv) -> Iv { + let c = [self.mul(a.lo, b.lo), self.mul(a.lo, b.hi), self.mul(a.hi, b.lo), self.mul(a.hi, b.hi)]; + let lo = c.iter().copied().fold(c[0], I512::min); + let hi = c.iter().copied().fold(c[0], I512::max); + Iv::new(lo, hi) + } + /// `R_round(p, s)` (§2), evaluated as §2 writes it. + fn round(&mut self, p: I512, s: u32, r: Round) -> I512 { + if s == 0 { + return p; + } + match r { + Round::Floor => self.shr(p, s), + Round::HalfUp => { + let t = self.add(p, I512::pow2(s - 1)); + self.shr(t, s) + } + Round::HalfEven => { + let q = self.shr(p, s); + let qs = self.mul(q, I512::pow2(s)); + let rem = self.sub(p, qs); + let h = I512::pow2(s - 1); + if rem > h || (rem == h && q.is_odd()) { self.add(q, I512::ONE) } else { q } + } + } + } + /// The `rq` rules for one channel (§8.3): `rq.p`, `rq.q` and `rq.y` from `rq.t`. + fn rq_chan(&mut self, t: Iv, m: Option, s: u32, r: Round, post: i64) -> (Iv, Iv, Iv) { + let m = i(m.unwrap_or(1)); + let (a, b) = (self.mul(t.lo, m), self.mul(t.hi, m)); + let p = Iv::new(a.min(b), a.max(b)); + let add = if r != Round::Floor && s >= 1 { I512::pow2(s - 1) } else { Z }; + let rp = Iv::new(p.lo, self.add(p.hi, add)); + let q = Iv::new(self.round(p.lo, s, r), self.round(p.hi, s, r)); + let y = Iv::new(self.add(q.lo, i(post)), self.add(q.hi, i(post))); + (rp, q, y) + } +} + +// ------------------------------------------------------------------ one node + +/// A named intermediate (§5, Table 8.5-A), its class and its interval (the hull over +/// channels). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Inter { + pub key: &'static str, + pub class: Class, + pub iv: Iv, +} + +/// One operator's rules applied to the intervals of its inputs. +pub(crate) struct Eval { + pub(crate) inter: Vec, + pub(crate) results: Vec, + pub(crate) saturated: bool, + /// `lut16`'s input range passes `[−32767, 32767]`: a load refusal (§5.6). + pub(crate) lut_range: bool, +} + +/// The `rq` intermediates and producer result of a whole requantisation, given each +/// channel's `rq.t`; the per-channel rules are hulled (§8.1). +fn rq_all(ar: &mut Ar, inter: &mut Vec, ts: &[Iv], rq: &Rq) -> Iv { + let (mut t, mut p, mut q, mut y) = (None, None, None, None); + for (o, &to) in ts.iter().enumerate() { + let (po, qo, yo) = ar.rq_chan(to, rq.mult(o), rq.shift(o), rq.round, rq.post(o)); + t = hull_opt(t, to); + p = hull_opt(p, po); + q = hull_opt(q, qo); + y = hull_opt(y, yo); + } + let (t, p, q, y) = (t.unwrap(), p.unwrap(), q.unwrap(), y.unwrap()); + inter.push(Inter { key: "rq.t", class: Class::Acc, iv: t }); + inter.push(Inter { key: "rq.p", class: Class::Product, iv: p }); + inter.push(Inter { key: "rq.q", class: Class::Acc, iv: q }); + inter.push(Inter { key: "rq.y", class: Class::Acc, iv: y }); + y +} + +/// The term hull and the partial-sum interval `A(K, b)` (§8.2) of the weights `ws` +/// over the input interval `x`. +fn taps(ar: &mut Ar, ws: &[i64], x: Iv, b: i64) -> (Iv, Iv) { + let bb = i(b); + let (mut lo, mut hi) = (bb.min(Z), bb.max(Z)); + let mut th: Option = None; + for &w in ws { + let t = ar.term(i(w), x); + th = hull_opt(th, t); + lo = ar.add(lo, t.lo.min(Z)); + hi = ar.add(hi, t.hi.max(Z)); + } + (th.unwrap_or(Iv::point(Z)), Iv::new(lo, hi)) +} + +/// The `exp_neg_q16` rule (§8.3), given the interval of `u = −x`. +fn exp_rule(ar: &mut Ar, inter: &mut Vec, uv: Iv) { + let k = u(45426); + let (nlo, nhi) = (ar.fdiv(uv.lo, k), ar.fdiv(uv.hi, k)); + let nl = Iv::new(ar.mul(k, nlo), ar.mul(k, nhi)); + let t2 = Iv::new(ar.mul(u(43245), u(43245)), ar.mul(u(88670), u(88670))); + let sq = ar.mul(u(88670), u(88670)); + let q = ar.shr(sq, 16); + let c = Iv::new(Z, ar.mul(u(23495), q)); + inter.push(Inter { key: "exp.negx", class: Class::Acc, iv: uv }); + inter.push(Inter { key: "exp.nl", class: Class::Acc, iv: nl }); + inter.push(Inter { key: "exp.t2", class: Class::Acc, iv: t2 }); + inter.push(Inter { key: "exp.c", class: Class::Acc, iv: c }); +} + +/// The size of a reduction (§8.1, *Sizes*): `H·W` or `W` of tensor `t`, planned on the +/// declared sizes. +fn size_of(sizes: Option<&[(u64, u64)]>, t: u32) -> (u64, u64) { + sizes.map(|s| s[t as usize]).unwrap_or((0, 0)) +} + +/// Apply operator `op`'s rules (§8.3) to `ins`, the intervals of its inputs in input +/// order. +pub(crate) fn eval(g: &Graph, op: &Op, ins: &[Iv], sizes: Option<&[(u64, u64)]>) -> Eval { + let mut ar = Ar::default(); + let mut inter: Vec = Vec::new(); + let x = ins[0]; + let cin = g.tensors[op.ins[0] as usize].channels as usize; + let mut lut_range = false; + let results: Vec = match (&op.p, op.code) { + (Params::Conv { cout, kh, kw, groups, rq, w, .. }, _) => { + let (cout, cg) = (*cout as usize, cin / *groups as usize); + let n = cg * *kh as usize * *kw as usize; + let (mut th, mut ah) = (None, None); + let mut ts = Vec::with_capacity(cout); + for o in 0..cout { + let (t, a) = taps(&mut ar, &w[o * n..(o + 1) * n], x, rq.pre(o)); + th = hull_opt(th, t); + ah = hull_opt(ah, a); + ts.push(a); + } + inter.push(Inter { key: "conv.term", class: Class::Acc, iv: th.unwrap() }); + inter.push(Inter { key: "conv.acc", class: Class::Acc, iv: ah.unwrap() }); + vec![rq_all(&mut ar, &mut inter, &ts, rq)] + } + (Params::ConvT { cout, kh, kw, sh, sw, rq, w, .. }, _) => { + let (cout, kh, kw, sh, sw) = (*cout as usize, *kh as usize, *kw as usize, *sh as usize, *sw as usize); + // Residues with no tap give A(∅, b), which every other residue's interval + // holds; the hull is over the residues that have taps. + let (rh, rw) = (sh.min(kh), sw.min(kw)); + let (mut th, mut ah) = (None, None); + let mut ts = Vec::with_capacity(cout); + for o in 0..cout { + let b = i(rq.pre(o)); + let mut buckets = vec![(b.min(Z), b.max(Z)); rh * rw]; + for ci in 0..cin { + for ii in 0..kh { + for jj in 0..kw { + let wv = w[((ci * cout + o) * kh + ii) * kw + jj]; + let t = ar.term(i(wv), x); + th = hull_opt(th, t); + let k = (ii % sh) * rw + (jj % sw); + let (lo, hi) = buckets[k]; + buckets[k] = (ar.add(lo, t.lo.min(Z)), ar.add(hi, t.hi.max(Z))); + } + } + } + let mut a: Option = None; + for &(lo, hi) in &buckets { + a = hull_opt(a, Iv::new(lo, hi)); + } + let a = a.unwrap(); + ah = hull_opt(ah, a); + ts.push(a); + } + inter.push(Inter { key: "convT.term", class: Class::Acc, iv: th.unwrap() }); + inter.push(Inter { key: "convT.acc", class: Class::Acc, iv: ah.unwrap() }); + vec![rq_all(&mut ar, &mut inter, &ts, rq)] + } + (Params::Rescale(rq), _) => { + let ts: Vec = (0..cin).map(|c| Iv::new(ar.add(x.lo, i(rq.pre(c))), ar.add(x.hi, i(rq.pre(c))))).collect(); + vec![rq_all(&mut ar, &mut inter, &ts, rq)] + } + (Params::Chscale { scalar, round, shift, m, .. }, _) => { + let s = g.scalars[*scalar as usize]; + let (mut p, mut q) = (None, None); + for c in 0..cin { + for row in s.lo..=s.hi { + let (po, qo, _) = ar.rq_chan(x, Some(m[row as usize * cin + c]), *shift as u32, *round, 0); + p = hull_opt(p, po); + q = hull_opt(q, qo); + } + } + let (p, q) = (p.unwrap(), q.unwrap()); + inter.push(Inter { key: "rq.t", class: Class::Acc, iv: x }); + inter.push(Inter { key: "rq.p", class: Class::Product, iv: p }); + inter.push(Inter { key: "rq.q", class: Class::Acc, iv: q }); + inter.push(Inter { key: "rq.y", class: Class::Acc, iv: q }); + vec![q] + } + (Params::Mul(rq), _) => { + let mp = ar.corner(x, ins[1]); + inter.push(Inter { key: "mul.p", class: Class::Acc, iv: mp }); + let ts = vec![mp; cin]; + vec![rq_all(&mut ar, &mut inter, &ts, rq)] + } + (Params::Gram { rq, .. }, _) => { + let t = ar.corner(x, ins[1]); + let (h0, w0) = size_of(sizes, op.ins[0]); + let (h1, w1) = size_of(sizes, op.ins[1]); + let l = u((h0 * w0).max(h1 * w1)); + let acc = Iv::new(ar.mul(l, t.lo.min(Z)), ar.mul(l, t.hi.max(Z))); + inter.push(Inter { key: "gram.term", class: Class::Acc, iv: t }); + inter.push(Inter { key: "gram.acc", class: Class::Acc, iv: acc }); + let ts = vec![acc; cin]; + vec![rq_all(&mut ar, &mut inter, &ts, rq)] + } + (Params::Apply { groups, rq }, _) => { + let t = ar.corner(x, ins[1]); + let d = u((cin / *groups as usize) as u64); + let acc = Iv::new(ar.mul(d, t.lo.min(Z)), ar.mul(d, t.hi.max(Z))); + inter.push(Inter { key: "apply.term", class: Class::Acc, iv: t }); + inter.push(Inter { key: "apply.acc", class: Class::Acc, iv: acc }); + let ts = vec![acc; cin]; + vec![rq_all(&mut ar, &mut inter, &ts, rq)] + } + (_, ADD) => vec![Iv::new(ar.add(x.lo, ins[1].lo), ar.add(x.hi, ins[1].hi))], + (_, CHUNK_ADD) => vec![Iv::new(ar.mul(u(2), x.lo), ar.mul(u(2), x.hi))], + (Params::Clamp { lo, hi }, _) => vec![Iv::new(ar.clamp(x.lo, i(*lo), i(*hi)), ar.clamp(x.hi, i(*lo), i(*hi)))], + (_, RELU) => vec![Iv::new(ar.max(x.lo, Z), ar.max(x.hi, Z))], + (_, ABS) => vec![abs_image(&mut ar, x)], + (Params::Leaky { a, f }, _) => { + let mut r: Option = None; + if x.lo.is_neg() { + let hn = ar.min(x.hi, i(-1)); + let p = ar.corner(Iv::new(x.lo, hn), Iv::point(i(*a))); + inter.push(Inter { key: "leaky.p", class: Class::Acc, iv: p }); + r = Some(Iv::new(ar.shr(p.lo, *f), ar.shr(p.hi, *f))); + } else { + inter.push(Inter { key: "leaky.p", class: Class::Acc, iv: Iv::point(Z) }); + } + if !x.hi.is_neg() { + let nn = Iv::new(ar.max(x.lo, Z), x.hi); + r = hull_opt(r, nn); + } + vec![r.unwrap()] + } + (Params::Lut16 { t, .. }, _) => { + if x.lo < i(-32767) || x.hi > i(32767) { + lut_range = true; + vec![Iv::point(Z)] + } else { + let (l, h) = (x.lo.to_i64().unwrap(), x.hi.to_i64().unwrap()); + let mut mn = i64::MAX; + let mut mx = i64::MIN; + for v in l..=h { + let e = t[(v + 32768) as usize] as i64; + mn = mn.min(e); + mx = mx.max(e); + } + vec![Iv::of_i64(mn, mx)] + } + } + (Params::Igdn { gf, frac, gamma, beta, .. }, _) => { + let (l2, h2) = (ar.mul(x.lo, x.lo), ar.mul(x.hi, x.hi)); + let x2 = if x.lo <= Z && Z <= x.hi { Iv::new(Z, l2.max(h2)) } else { Iv::new(l2.min(h2), l2.max(h2)) }; + let c = cin; + let (mut gx, mut tm, mut nn, mut rr, mut xr, mut res) = (None, None, None, None, None, None); + for oi in 0..c { + let b = i(beta[oi]); + let (mut plo, mut phi) = (b.min(Z), b.max(Z)); + let (mut flo, mut fhi) = (b, b); + for j in 0..c { + let gv = i(gamma[oi * c + j]); + let g2 = ar.corner(Iv::point(gv), x2); + gx = hull_opt(gx, g2); + let t = Iv::new(ar.shr(g2.lo, *gf), ar.shr(g2.hi, *gf)); + tm = hull_opt(tm, t); + plo = ar.add(plo, t.lo.min(Z)); + phi = ar.add(phi, t.hi.max(Z)); + flo = ar.add(flo, t.lo); + fhi = ar.add(fhi, t.hi); + } + nn = hull_opt(nn, Iv::new(plo, phi)); + let (a, b2) = (ar.max(Z, flo), ar.max(Z, fhi)); + let r = Iv::new(ar.isqrt(a), ar.isqrt(b2)); + rr = hull_opt(rr, r); + let p = ar.corner(x, r); + xr = hull_opt(xr, p); + res = hull_opt(res, Iv::new(ar.shr(p.lo, *frac), ar.shr(p.hi, *frac))); + } + inter.push(Inter { key: "igdn.x2", class: Class::Wide, iv: x2 }); + inter.push(Inter { key: "igdn.gx2", class: Class::Product, iv: gx.unwrap() }); + inter.push(Inter { key: "igdn.term", class: Class::Wide, iv: tm.unwrap() }); + inter.push(Inter { key: "igdn.N", class: Class::Wide, iv: nn.unwrap() }); + inter.push(Inter { key: "igdn.r", class: Class::Acc, iv: rr.unwrap() }); + inter.push(Inter { key: "igdn.xr", class: Class::Wide, iv: xr.unwrap() }); + vec![res.unwrap()] + } + (Params::LayerNorm { eps, gamma, beta, .. }, _) => { + let cc = u(cin as u64); + let e = u(*eps); + let (l, h) = (x.lo, x.hi); + let s = Iv::new(ar.mul(cc, l.min(Z)), ar.mul(cc, h.max(Z))); + let half = ar.fdiv(cc, u(2)); + let cl = ar.mul(cc, l); + let ch = ar.mul(cc, h); + let m = Iv::new(ar.sub(cl, half), ar.add(ch, half)); + let d = Iv::new(ar.sub(l, h), ar.sub(h, l)); + let dd = ar.sub(h, l); + let sq = ar.mul(dd, dd); + let t = Iv::new(Z, ar.mul(cc, sq)); + let v = Iv::new(e, ar.add(sq, e)); + let num = I512::pow2(32); + let r0 = ar.isqrt(e); + let k32 = ar.fdiv(num, r0); + let k = Iv::new(Z, k32); + let ic = ar.isqrt_ceil(cc); + let r1 = ar.add(r0, I512::ONE); + let d1 = ar.mul(dd, k32); + let a0 = ar.mul(ic, num); + let a1 = ar.mul(a0, r1); + let na1 = ar.neg(a1); + let fl = ar.fdiv(na1, r0); + let d2 = ar.neg(fl); + let dmax = ar.min(d1, d2); + let dk = Iv::new(ar.neg(dmax), dmax); + let n1s = ar.shr(d1, 16); + let n1 = ar.add(n1s, I512::ONE); + let b0 = ar.mul(ic, I512::pow2(16)); + let b1 = ar.mul(b0, r1); + let b2 = ar.fdiv(b1, r0); + let nmax = ar.add(b2, I512::ONE); + let nn = ar.min(n1, nmax); + let n = Iv::new(ar.neg(nn), nn); + let (mut ng, mut res) = (None, None); + for c in 0..cin { + let gv = Iv::point(i(gamma[c])); + let p = ar.corner(n, gv); + ng = hull_opt(ng, p); + let (a, b) = (ar.shr(p.lo, 16), ar.shr(p.hi, 16)); + res = hull_opt(res, Iv::new(ar.add(a, i(beta[c])), ar.add(b, i(beta[c])))); + } + inter.push(Inter { key: "ln.S", class: Class::Wide, iv: s }); + inter.push(Inter { key: "ln.m", class: Class::Wide, iv: m }); + inter.push(Inter { key: "ln.d", class: Class::Acc, iv: d }); + inter.push(Inter { key: "ln.T", class: Class::Wide, iv: t }); + inter.push(Inter { key: "ln.v", class: Class::Wide, iv: v }); + inter.push(Inter { key: "rsq.num", class: Class::Acc, iv: Iv::point(num) }); + inter.push(Inter { key: "ln.k", class: Class::Acc, iv: k }); + inter.push(Inter { key: "ln.dk", class: Class::Wide, iv: dk }); + inter.push(Inter { key: "ln.n", class: Class::Acc, iv: n }); + inter.push(Inter { key: "ln.ng", class: Class::Wide, iv: ng.unwrap() }); + vec![res.unwrap()] + } + (Params::L2norm { eps }, _) => { + let (hh, ww) = size_of(sizes, op.ins[0]); + let l = u(hh * ww); + let e = u(*eps); + let (al, ah) = (ar.abs(x.lo), ar.abs(x.hi)); + let xm = ar.max(al, ah); + let x2 = ar.mul(xm, xm); + let lx2 = ar.mul(l, x2); + let t = Iv::new(Z, ar.add(lx2, e)); + let num = I512::pow2(32); + let r0 = ar.isqrt(e); + let k = Iv::new(Z, ar.fdiv(num, r0)); + inter.push(Inter { key: "l2.T", class: Class::Wide, iv: t }); + inter.push(Inter { key: "rsq.num", class: Class::Acc, iv: Iv::point(num) }); + inter.push(Inter { key: "l2.k", class: Class::Acc, iv: k }); + inter.push(Inter { key: "l2.vk", class: Class::Wide, iv: Iv::new(num.neg(), num) }); + vec![Iv::new(I512::pow2(16).neg(), I512::pow2(16))] + } + (_, SOFTMAX) => { + let wmax = u(size_of(sizes, op.ins[0]).1); + let diff = Iv::new(ar.sub(x.lo, x.hi), Z); + inter.push(Inter { key: "sm.diff", class: Class::Acc, iv: diff }); + let uv = Iv::new(Z, ar.sub(x.hi, x.lo)); + exp_rule(&mut ar, &mut inter, uv); + let sum = Iv::new(Z, ar.mul(wmax, u(65553))); + let a = ar.mul(u(65553), I512::pow2(16)); + let b0 = ar.mul(wmax, u(65553)); + let b = ar.fdiv(b0, u(2)); + let num = Iv::new(Z, ar.add(a, b)); + inter.push(Inter { key: "sm.sum", class: Class::Acc, iv: sum }); + inter.push(Inter { key: "sm.num", class: Class::Acc, iv: num }); + vec![Iv::new(Z, I512::pow2(16))] + } + (_, SIGMOID) => { + let uv = abs_image(&mut ar, x); + exp_rule(&mut ar, &mut inter, uv); + let num = Iv::new(Z, ar.mul(u(65553), I512::pow2(16))); + inter.push(Inter { key: "sig.num", class: Class::Acc, iv: num }); + vec![Iv::new(Z, I512::pow2(16))] + } + (Params::Elu { alpha }, _) => { + let (nh, nl) = (ar.neg(x.hi), ar.neg(x.lo)); + let uv = Iv::new(ar.max(Z, nh), ar.max(Z, nl)); + exp_rule(&mut ar, &mut inter, uv); + let p = ar.corner(Iv::point(i(*alpha)), Iv::new(I512::pow2(16).neg(), u(17))); + inter.push(Inter { key: "elu.p", class: Class::Wide, iv: p }); + let mut r: Option = None; + if x.hi > Z { + r = Some(Iv::new(ar.max(x.lo, I512::ONE), x.hi)); + } + if x.lo <= Z { + let q = Iv::new(ar.shr(p.lo, 16), ar.shr(p.hi, 16)); + r = hull_opt(r, q); + } + vec![r.unwrap()] + } + (_, CONCAT) | (_, SUBPOS_MERGE) => { + let mut r = x; + for &v in &ins[1..] { + r = r.hull(v); + } + vec![r] + } + (Params::Fill { kind, value }, _) => { + if *kind == 0 { + vec![Iv::point(i(*value))] + } else { + let s = g.scalars[*value as usize]; + vec![Iv::of_i64(s.lo, s.hi)] + } + } + // Every other operator moves its first input's values (`crop_to` included). + _ => vec![x; op.outs.len()], + }; + Eval { inter, results, saturated: ar.hit, lut_range } +} + +/// The image of an interval under `|·|` (§8.3). +fn abs_image(ar: &mut Ar, x: Iv) -> Iv { + if !x.lo.is_neg() { + x + } else if x.hi <= Z { + Iv::new(ar.neg(x.hi), ar.neg(x.lo)) + } else { + let nl = ar.neg(x.lo); + Iv::new(Z, ar.max(nl, x.hi)) + } +} + +// ------------------------------------------------------------------ parameters, flags + +fn fits32(v: i64) -> bool { + i32::try_from(v).is_ok() +} + +/// The parameter conditions of §7.2 a node fails, in that table's order. +fn params32(op: &Op) -> Vec<&'static str> { + let mut v = Vec::new(); + let rq_keys = |v: &mut Vec<&'static str>, rq: &Rq| { + if !rq.mult.iter().all(|&m| fits32(m)) { + v.push("rq.mult"); + } + if !rq.shift.iter().all(|&s| s <= 63) { + v.push("rq.shift"); + } + if rq.bias_kind == BiasKind::Post && !rq.bias.iter().all(|&b| fits32(b)) { + v.push("rq.post_bias"); + } + }; + match &op.p { + Params::Conv { rq, w, .. } | Params::ConvT { rq, w, .. } => { + rq_keys(&mut v, rq); + if !w.iter().all(|&x| fits32(x)) { + v.push("weights"); + } + } + Params::Rescale(rq) | Params::Mul(rq) | Params::Gram { rq, .. } | Params::Apply { rq, .. } => rq_keys(&mut v, rq), + Params::Chscale { shift, m, .. } => { + if !m.iter().all(|&x| fits32(x)) { + v.push("chscale.m"); + } + if *shift > 63 { + v.push("chscale.s"); + } + } + Params::Igdn { gf, frac, gamma, .. } => { + if !gamma.iter().all(|&x| fits32(x)) { + v.push("igdn.gamma"); + } + if *gf > 63 || *frac > 63 { + v.push("igdn.shift"); + } + } + Params::Leaky { a, .. } => { + if !fits32(*a) { + v.push("leaky.a"); + } + } + _ => {} + } + v +} + +/// The node's flags of §9.2, in ascending order. +fn npu_flags(g: &Graph, op: &Op) -> Vec<&'static str> { + let mut v: Vec<&'static str> = Vec::new(); + let rq_flags = |v: &mut Vec<&'static str>, round: Round, mult: Option<&[i64]>, bias_post: bool, shifts: &[u8]| { + if round == Round::HalfEven { + v.push("rq_half_even"); + } + if round == Round::Floor && mult.is_some() { + v.push("rq_floor_mult"); + } + if bias_post { + v.push("rq_post_bias"); + } + if mult.is_some_and(|m| m.iter().any(|&x| x < 0)) { + v.push("rq_neg_mult"); + } + if shifts.iter().any(|&s| s > 31) { + v.push("rq_shift_range"); + } + }; + match &op.p { + Params::Conv { rq, .. } | Params::ConvT { rq, .. } | Params::Rescale(rq) | Params::Mul(rq) | Params::Gram { rq, .. } | Params::Apply { rq, .. } => { + let m = if rq.m_kind == 0 { None } else { Some(rq.mult.as_slice()) }; + rq_flags(&mut v, rq.round, m, rq.bias_kind == BiasKind::Post, &rq.shift); + } + Params::Chscale { round, shift, m, .. } => { + v.push("chscale"); + rq_flags(&mut v, *round, Some(m.as_slice()), false, &[*shift]); + } + Params::Lut16 { .. } => v.push("lut16"), + _ => {} + } + if (op.code == ADD || op.code == CHUNK_ADD) && op.ins.iter().any(|&t| g.inputs.iter().any(|i| i.tensor == t && i.kind == 1)) { + v.push("state_add"); + } + v.sort_unstable_by(|a, b| a.as_bytes().cmp(b.as_bytes())); + v.dedup(); + v +} + +/// `K_c` (§6) over a term interval: `None` when it is unbounded (`P = 0`). +pub(crate) fn k_c(term: &Iv) -> Option { + let p = term.lo.abs().max(term.hi.abs()); + if p.is_zero() { None } else { Some(I512::from_i64(i32::MAX as i64).div_floor(p)) } +} + +// ------------------------------------------------------------------ the pass + +/// One node of the pass (§8.5's `node`). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Node { + pub index: u32, + pub code: u8, + pub saturated: bool, + /// Table 8.5-A's intermediates, in its definition order. + pub inter: Vec, + /// Each output's producer result. + pub results: Vec, + /// Each output's tensor, policy, and interval after the policy. + pub outs: Vec<(u32, Policy, Iv)>, + /// The parameter conditions of §7.2 the node fails. + pub params32: Vec<&'static str>, + /// `K_c`: absent for an operator without a term interval; `Some(None)` unbounded. + pub k_c: Option>, + /// `mac.a_bits`, for the operators that record it. + pub a_bits: Option>, + /// `mac.w_bits`, for `conv`, `conv_transpose` and `chscale`. + pub w_bits: Option, + pub npu_flags: Vec<&'static str>, +} + +/// Why a node, an input or a scalar does not meet a profile: its key, and the bits of +/// the failing interval when the key names one (§8.5, *First failure*). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Miss { + pub key: String, + pub bits: Option, +} + +impl Node { + /// The node's failure under `p`, or `None` when it fits `p` (§8.5). + pub fn miss(&self, p: Profile) -> Option { + if self.saturated { + return Some(Miss { key: "saturated".to_string(), bits: None }); + } + let mut best: Option<(u32, String)> = None; + let mut consider = |key: String, bits: u32, width: u32| { + if bits > width { + let better = match &best { + None => true, + Some((b, k)) => bits > *b || (bits == *b && key.as_bytes() < k.as_bytes()), + }; + if better { + best = Some((bits, key)); + } + } + }; + for it in &self.inter { + consider(it.key.to_string(), it.iv.bits(), it.class.width(p)); + } + for (k, r) in self.results.iter().enumerate() { + consider(format!("out.{k}"), r.bits(), Class::Tensor.width(p)); + } + if let Some((bits, key)) = best { + return Some(Miss { key, bits: Some(bits) }); + } + if p == Profile::Acc32 { + if let Some(k) = self.params32.first() { + return Some(Miss { key: k.to_string(), bits: None }); + } + if self.outs.iter().any(|o| o.1 == Policy::Check) { + return Some(Miss { key: "policy.check".to_string(), bits: None }); + } + } + None + } + + pub fn fits(&self, p: Profile) -> bool { + self.miss(p).is_none() + } +} + +/// The bounds pass over one graph. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Bounds { + pub nodes: Vec, + /// Every tensor's interval, after its policy. + pub tensors: Vec, +} + +/// Where a first failure lies (§8.5). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Where { + Input, + Scalar, + Node, +} + +impl Where { + pub fn as_str(self) -> &'static str { + match self { + Where::Input => "input", + Where::Scalar => "scalar", + Where::Node => "node", + } + } +} + +/// A graph's first failure under a profile (the role is the certificate's). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Failure { + pub at: Where, + pub index: u32, + pub miss: Miss, +} + +impl Bounds { + /// The first input, scalar or node of `g` that does not meet `p` (§8.5). + pub fn first_failure(&self, g: &Graph, p: Profile) -> Option { + let w = Class::Tensor.width(p); + for (k, inp) in g.inputs.iter().enumerate() { + let t = &g.tensors[inp.tensor as usize]; + let iv = Iv::of_i64(t.lo, t.hi); + if !iv.fits(w) { + return Some(Failure { at: Where::Input, index: k as u32, miss: Miss { key: "range".to_string(), bits: Some(iv.bits()) } }); + } + } + for (k, s) in g.scalars.iter().enumerate() { + let iv = Iv::of_i64(s.lo, s.hi); + if !iv.fits(w) { + return Some(Failure { at: Where::Scalar, index: k as u32, miss: Miss { key: "range".to_string(), bits: Some(iv.bits()) } }); + } + } + for n in &self.nodes { + if let Some(m) = n.miss(p) { + return Some(Failure { at: Where::Node, index: n.index, miss: m }); + } + } + None + } + + /// Whether `g` meets `p`. + pub fn meets(&self, g: &Graph, p: Profile) -> bool { + self.first_failure(g, p).is_none() + } +} + +/// An observer ([`crate::interp::Observe`]) that holds a run to a pass: every value an +/// operator forms under a named intermediate, and every element of a producer result, +/// must lie in the interval the pass records for it. It counts what it sees, keeps +/// each value outside its interval and each key the node does not record, and keeps +/// the extreme values seen for each node and key, so a caller can tell an interval +/// that is attained from one that is only an upper bound. +pub struct Within<'a> { + b: &'a Bounds, + pub seen: u64, + pub outside: Vec<(u32, &'static str, i128)>, + pub unrecorded: Vec<(u32, &'static str)>, + /// Per node: each key's interval (`None` when the node does not record the key) + /// and the smallest and largest value seen under it. + seen_at: Vec, i128, i128)>>, +} + +impl<'a> Within<'a> { + pub fn new(b: &'a Bounds) -> Within<'a> { + Within { b, seen: 0, outside: Vec::new(), unrecorded: Vec::new(), seen_at: vec![Vec::new(); b.nodes.len()] } + } + /// The smallest and largest value seen for `key` at node `op`. + pub fn extreme(&self, op: u32, key: &str) -> Option<(i128, i128)> { + self.seen_at.get(op as usize)?.iter().find(|e| e.0 == key).map(|e| (e.2, e.3)) + } +} + +impl crate::interp::Observe for Within<'_> { + fn see(&mut self, op: u32, key: &'static str, v: i128) { + self.seen += 1; + let slots = &mut self.seen_at[op as usize]; + let k = match slots.iter().position(|e| e.0 == key) { + Some(k) => k, + None => { + let n = &self.b.nodes[op as usize]; + let iv = match key.strip_prefix("out.") { + Some(o) => o.parse::().ok().and_then(|o| n.results.get(o).copied()), + None => n.inter.iter().find(|i| i.key == key).map(|i| i.iv), + }; + if iv.is_none() { + self.unrecorded.push((op, key)); + } + slots.push((key, iv, v, v)); + slots.len() - 1 + } + }; + let e = &mut slots[k]; + e.2 = e.2.min(v); + e.3 = e.3.max(v); + if let Some(iv) = e.1 { + let x = I512::from_i128(v); + if (x < iv.lo || x > iv.hi) && self.outside.len() < 16 { + self.outside.push((op, key, v)); + } + } + } +} + +fn refuse8() -> Refusal { + Refusal::new(Code::ModelMismatch, Site::Load(8)) +} + +/// The bounds pass (§8.1–§8.3) over `g`, with `sizes` the load plan's (§10.5 step 7). +/// It refuses (`model_mismatch`, load step 8) a `check` range that no value of its +/// producer can meet, and a `lut16` whose input range passes `[−32767, 32767]`. +pub fn pass(g: &Graph, sizes: Option<&[(u64, u64)]>) -> Result { + pass_with(g, sizes, &[]) +} + +/// The pass with some tensors' intervals replaced, after their policy (for §8.4's +/// search and for `--advise`). +pub fn pass_with(g: &Graph, sizes: Option<&[(u64, u64)]>, over: &[(u32, Iv)]) -> Result { + let nt = g.tensors.len(); + let mut iv: Vec = vec![Iv::point(Z); nt]; + let set = |iv: &mut Vec, t: u32, v: Iv| { + iv[t as usize] = over.iter().rev().find(|(o, _)| *o == t).map_or(v, |(_, x)| *x); + }; + for inp in &g.inputs { + let t = &g.tensors[inp.tensor as usize]; + set(&mut iv, inp.tensor, Iv::of_i64(t.lo, t.hi)); + } + let mut nodes = Vec::with_capacity(g.ops.len()); + for (k, op) in g.ops.iter().enumerate() { + let ins: Vec = op.ins.iter().map(|&t| iv[t as usize]).collect(); + let e = eval(g, op, &ins, sizes); + if e.lut_range { + return Err(refuse8()); + } + let mut outs = Vec::with_capacity(op.outs.len()); + for (&t, r) in op.outs.iter().zip(&e.results) { + let rec = &g.tensors[t as usize]; + let (lo, hi) = (i(rec.lo), i(rec.hi)); + let after = match rec.policy { + Policy::Derived => *r, + Policy::Clamp => Iv::new(r.lo.max(lo).min(hi), r.hi.max(lo).min(hi)), + Policy::Check => { + let a = Iv::new(r.lo.max(lo), r.hi.min(hi)); + if a.lo > a.hi { + return Err(refuse8()); + } + a + } + }; + set(&mut iv, t, after); + outs.push((t, rec.policy, iv[t as usize])); + } + let term = e.inter.iter().find(|x| matches!(x.key, "conv.term" | "convT.term" | "igdn.term" | "gram.term" | "apply.term")).map(|x| x.iv); + let a_bits = match op.code { + CONV | CONV_TRANSPOSE | CHSCALE | MUL | GRAM | APPLY => Some(ins.iter().map(Iv::bits).collect()), + _ => None, + }; + let w_bits = match &op.p { + Params::Conv { w, .. } | Params::ConvT { w, .. } | Params::Chscale { m: w, .. } => { + let (mn, mx) = (w.iter().copied().min().unwrap_or(0), w.iter().copied().max().unwrap_or(0)); + Some(Iv::of_i64(mn, mx).bits()) + } + _ => None, + }; + nodes.push(Node { + index: k as u32, + code: op.code, + saturated: e.saturated, + inter: e.inter, + results: e.results, + outs, + params32: params32(op), + k_c: term.map(|t| k_c(&t)), + a_bits, + w_bits, + npu_flags: npu_flags(g, op), + }); + } + Ok(Bounds { nodes, tensors: iv }) +} + +/// Load step 8 for one graph that passed steps 1–7, with `sizes` the plan's: the +/// pass, then the profile against the verdict (§8.6). The result is the pass. +pub fn step8(g: &Graph, sizes: Option<&[(u64, u64)]>, p: Profile) -> Result { + let b = pass(g, sizes)?; + if !b.meets(g, p) { + return Err(refuse8()); + } + Ok(b) +} + +// ------------------------------------------------------------------ admissible ranges + +/// The admissible range of tensor `t` for `p` (§8.4), given the pass `b` over `g`: +/// `None` when `t` has none. +pub fn admissible(g: &Graph, sizes: Option<&[(u64, u64)]>, b: &Bounds, t: u32, p: Profile) -> Option { + let consumers: Vec<&Op> = g.ops.iter().filter(|o| o.ins.contains(&t)).collect(); + let cond = |x: u128| -> bool { + let xv = I512::from_u128(x); + let r = Iv::new(xv.neg(), xv); + consumers.iter().all(|op| { + let ins: Vec = op.ins.iter().map(|&s| if s == t { r } else { b.tensors[s as usize] }).collect(); + let e = eval(g, op, &ins, sizes); + !e.saturated && !e.lut_range && e.inter.iter().all(|x| x.iv.fits(x.class.width(p))) && e.results.iter().all(|x| x.fits(Class::Tensor.width(p))) + }) + }; + let x = crate::lower::largest(cond)?; + let xv = I512::from_u128(x); + Some(Iv::new(xv.neg(), xv.min(I512::from_i64(i64::MAX)))) +} + +/// One tensor's advice for `--advise` (Part 2.3 of the design): its interval, its +/// admissible range, and the clamp proposed where its consumers fail. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Advice { + pub tensor: u32, + pub interval: Iv, + pub admissible: Option, + pub clamp: Option, +} + +/// Walk `g` in tensor order. At each tensor whose interval passes its admissible +/// range for `p`, propose a `clamp` at that range and carry the clamped interval +/// downstream, so that later tensors are judged after the clamps before them. +pub fn advise(g: &Graph, sizes: Option<&[(u64, u64)]>, p: Profile) -> Result, Refusal> { + let mut over: Vec<(u32, Iv)> = Vec::new(); + let mut b = pass_with(g, sizes, &over)?; + let mut out = Vec::new(); + for t in 0..g.tensors.len() as u32 { + let cur = b.tensors[t as usize]; + let adm = admissible(g, sizes, &b, t, p); + let clamp = match adm { + Some(a) if !a.holds(&cur) => Some(a), + _ => None, + }; + out.push(Advice { tensor: t, interval: cur, admissible: adm, clamp }); + if let Some(a) = clamp { + let c = Iv::new(cur.lo.max(a.lo).min(a.hi), cur.hi.max(a.lo).min(a.hi)); + over.push((t, c)); + b = pass_with(g, sizes, &over)?; + } + } + Ok(out) +} + +// ------------------------------------------------------------------ the certificate + +/// One graph of a certificate: its role, its bytes' digest, the graph and its pass. +#[derive(Clone, Debug)] +pub struct CertGraph { + pub name: String, + pub sha256: String, + pub graph: Graph, + pub sizes: Option>, + pub bounds: Bounds, +} + +/// A first failure with the role of the graph it lies in. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SetFailure { + pub graph: String, + pub failure: Failure, +} + +/// A set's verdict (§8.5). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Verdict { + pub acc32: Option, + pub acc64: Option, + pub npu_flags: Vec, + pub npu_reasons: Vec, +} + +impl Verdict { + /// Whether the set meets `p`. + pub fn meets(&self, p: Profile) -> bool { + match p { + Profile::Acc32 => self.acc32.is_none(), + Profile::Acc64 => self.acc64.is_none(), + } + } + /// The first failure under `p`, if it fails. + pub fn failure(&self, p: Profile) -> Option<&SetFailure> { + match p { + Profile::Acc32 => self.acc32.as_ref(), + Profile::Acc64 => self.acc64.as_ref(), + } + } + pub fn npu(&self) -> bool { + self.npu_reasons.is_empty() + } +} + +/// A bounds certificate (§8.5): one parameter set's graphs, each with its pass. +#[derive(Clone, Debug)] +pub struct Certificate { + pub capability: Option, + pub lowering: String, + pub set_sha256: Option, + pub graphs: Vec, +} + +/// Why a set could not be certified: the graph (its position and role) and the load +/// refusal it met at steps 1–8, before any verdict. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Uncertifiable { + pub graph: usize, + pub name: String, + pub refusal: Refusal, +} + +/// Certify a set's graphs, given as `(role, WHG1 bytes)` in the lowering's role order +/// (or file order for `"whg1"`). Each graph passes load steps 1–7 and the pass's own +/// refusals; the profile is not applied, the verdict records it. +pub fn certify(capability: Option<&str>, lowering: &str, set_sha256: Option<&str>, graphs: &[(&str, &[u8])]) -> Result { + let mut out = Vec::with_capacity(graphs.len()); + for (k, (name, bytes)) in graphs.iter().enumerate() { + let fail = |r: Refusal| Uncertifiable { graph: k, name: name.to_string(), refusal: r }; + let g = Graph::parse(bytes).map_err(fail)?; + let sizes = crate::plan::load_plan(&g).map_err(fail)?; + let b = pass(&g, sizes.as_deref()).map_err(fail)?; + out.push(CertGraph { name: name.to_string(), sha256: json::hex(&sha256(bytes)), graph: g, sizes, bounds: b }); + } + Ok(Certificate { capability: capability.map(String::from), lowering: lowering.to_string(), set_sha256: set_sha256.map(String::from), graphs: out }) +} + +/// The `npu_reasons` of one graph (§8.5), before the `acc32` reason. +fn npu_reasons(g: &Graph) -> Vec { + let mut v = Vec::new(); + for op in &g.ops { + match op.code { + IGDN | LAYERNORM_C | L2NORM | SOFTMAX | SIGMOID | ELU | GRAM | APPLY => v.push(format!("op:{}", op_name(op.code).unwrap_or("?"))), + _ => {} + } + if let Params::Conv { groups, cout, .. } = &op.p { + let cin = g.tensors[op.ins[0] as usize].channels; + if (*groups != 1 && *groups != cin) || (*groups == cin && *groups > 1 && *cout != cin) { + v.push("conv_groups".to_string()); + } + } + if let Params::Crop { y0, x0, h, w } = &op.p + && [y0, x0, h, w].iter().any(|o| matches!(o, Operand::Scalar(_))) + { + v.push("crop_scalar".to_string()); + } + } + v +} + +fn sort_dedup(v: &mut Vec) { + v.sort_unstable_by(|a, b| a.as_bytes().cmp(b.as_bytes())); + v.dedup(); +} + +impl Certificate { + /// The verdict (§8.5). + pub fn verdict(&self) -> Verdict { + let first = |p: Profile| { + self.graphs.iter().find_map(|cg| cg.bounds.first_failure(&cg.graph, p).map(|f| SetFailure { graph: cg.name.clone(), failure: f })) + }; + let acc32 = first(Profile::Acc32); + let acc64 = first(Profile::Acc64); + let mut reasons: Vec = Vec::new(); + let mut flags: Vec = Vec::new(); + for cg in &self.graphs { + reasons.extend(npu_reasons(&cg.graph)); + for n in &cg.bounds.nodes { + flags.extend(n.npu_flags.iter().map(|s| s.to_string())); + } + } + if acc32.is_some() { + reasons.push("acc32".to_string()); + } + sort_dedup(&mut reasons); + sort_dedup(&mut flags); + Verdict { acc32, acc64, npu_flags: flags, npu_reasons: reasons } + } + + /// The certificate as canonical JSON (§8.5): no whitespace, no final line feed. + pub fn to_json(&self) -> String { + json::to_string(&self.to_c()) + } + + pub fn to_c(&self) -> C { + let v = self.verdict(); + let failure = |f: &SetFailure| { + let mut m = vec![ + ("graph", C::s(&f.graph)), + ("index", C::int(f.failure.index as i128)), + ("key", C::s(&f.failure.miss.key)), + ("where", C::s(f.failure.at.as_str())), + ]; + if let Some(b) = f.failure.miss.bits { + m.push(("bits", C::int(b as i128))); + } + C::obj(m) + }; + let mut vm = vec![ + ("acc32", C::Bool(v.acc32.is_none())), + ("acc64", C::Bool(v.acc64.is_none())), + ("npu", C::Bool(v.npu())), + ("npu_flags", C::Arr(v.npu_flags.iter().map(|s| C::s(s)).collect())), + ("npu_reasons", C::Arr(v.npu_reasons.iter().map(|s| C::s(s)).collect())), + ]; + if let Some(f) = &v.acc32 { + vm.push(("acc32_first_failure", failure(f))); + } + if let Some(f) = &v.acc64 { + vm.push(("acc64_first_failure", failure(f))); + } + C::obj(vec![ + ("capability", self.capability.as_deref().map_or(C::Null, C::s)), + ("certificate", C::s("wai-ops/1 bounds")), + ("graphs", C::Arr(self.graphs.iter().map(graph_c).collect())), + ("lowering", C::s(&self.lowering)), + ("set_sha256", self.set_sha256.as_deref().map_or(C::Null, C::s)), + ("verdict", C::obj(vm)), + ]) + } +} + +/// `{ "bits", "hi", "lo" }`. +pub fn iv_c(iv: &Iv) -> C { + C::obj(vec![("bits", C::int(iv.bits() as i128)), ("hi", C::big(iv.hi)), ("lo", C::big(iv.lo))]) +} + +fn policy_str(p: Policy) -> &'static str { + match p { + Policy::Derived => "derived", + Policy::Clamp => "clamp", + Policy::Check => "check", + } +} + +fn graph_c(cg: &CertGraph) -> C { + let g = &cg.graph; + let inputs = g + .inputs + .iter() + .map(|inp| { + let t = &g.tensors[inp.tensor as usize]; + let mut m = vec![ + ("hi", C::int(t.hi as i128)), + ("kind", C::s(if inp.kind == 1 { "state" } else { "data" })), + ("lo", C::int(t.lo as i128)), + ("max_h", C::int(inp.max_h as i128)), + ("max_w", C::int(inp.max_w as i128)), + ("policy", C::s(policy_str(t.policy))), + ("tensor", C::int(inp.tensor as i128)), + ]; + if inp.kind == 1 { + m.push(("init", C::int(inp.init as i128))); + m.push(("src", C::int(inp.src as i128))); + } + C::obj(m) + }) + .collect(); + let scalars = g.scalars.iter().enumerate().map(|(k, s)| C::obj(vec![("hi", C::int(s.hi as i128)), ("index", C::int(k as i128)), ("lo", C::int(s.lo as i128))])).collect(); + C::obj(vec![ + ("graph_sha256", C::s(&cg.sha256)), + ("inputs", C::Arr(inputs)), + ("name", C::s(&cg.name)), + ("nodes", C::Arr(cg.bounds.nodes.iter().map(node_c).collect())), + ("scalars", C::Arr(scalars)), + ]) +} + +fn node_c(n: &Node) -> C { + let fits: Vec = Profile::ALL.iter().filter(|p| n.fits(**p)).map(|p| C::s(p.as_str())).collect(); + let inter = C::Obj(n.inter.iter().map(|x| (x.key.to_string(), iv_c(&x.iv))).collect()); + let outs = n + .outs + .iter() + .zip(&n.results) + .map(|((t, pol, iv), r)| { + C::obj(vec![ + ("bits", C::int(iv.bits() as i128)), + ("hi", C::big(iv.hi)), + ("lo", C::big(iv.lo)), + ("policy", C::s(policy_str(*pol))), + ("result", iv_c(r)), + ("tensor", C::int(*t as i128)), + ]) + }) + .collect(); + let mut m = vec![ + ("acc32_params", C::Arr(n.params32.iter().map(|s| C::s(s)).collect())), + ("fits", C::Arr(fits)), + ("index", C::int(n.index as i128)), + ("intermediates", inter), + ("npu_flags", C::Arr(n.npu_flags.iter().map(|s| C::s(s)).collect())), + ("op", C::s(op_name(n.code).unwrap_or("?"))), + ("out", C::Arr(outs)), + ("saturated", C::Bool(n.saturated)), + ]; + if let Some(k) = &n.k_c { + m.push(("k_c", match k { + None => C::s("unbounded"), + Some(v) => C::big(*v), + })); + } + if let Some(a) = &n.a_bits { + let mut mac = vec![("a_bits", C::ints(a.iter().map(|&b| b as i128)))]; + if let Some(w) = n.w_bits { + mac.push(("w_bits", C::int(w as i128))); + } + m.push(("mac", C::obj(mac))); + } + C::obj(m) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::graph::{CAP, InputRec, ScalarRec, TensorRec}; + + fn x(v: i128) -> I512 { + I512::from_i128(v) + } + fn iv(lo: i128, hi: i128) -> Iv { + Iv::new(x(lo), x(hi)) + } + fn input(t: u32) -> InputRec { + InputRec { tensor: t, max_h: 0, max_w: 0, kind: 0, src: 0, init: 0 } + } + /// A graph of one operator reading tensors `0..ins.len()` and writing the next. + fn one(code: u8, ins: Vec, out: TensorRec, p: Params) -> Graph { + let n = ins.len() as u32; + let mut tensors = ins; + tensors.push(out); + Graph { + max_elems: CAP as u32, + scalars: vec![], + inputs: (0..n).map(input).collect(), + outputs: vec![n], + tensors, + ops: vec![Op { code, ins: (0..n).collect(), outs: vec![n], p }], + } + } + fn get(n: &Node, key: &str) -> Iv { + n.inter.iter().find(|i| i.key == key).unwrap_or_else(|| panic!("no {key}")).iv + } + fn rq(round: Round, bias: BiasKind, b: Vec, m: Option>, s: u8) -> Rq { + let (m_kind, m_bytes, mult) = match m { + None => (0, 0, vec![]), + Some(v) if v.len() == 1 => (1, 8, v), + Some(v) => (2, 8, v), + }; + let b_bytes = if bias == BiasKind::None { 0 } else { 8 }; + Rq { round, bias_kind: bias, m_kind, s_kind: 1, m_bytes, b_bytes, mult, shift: vec![s], bias: b } + } + + /// A 1×1 convolution over two input channels: the term hull, `A(K, b)` with a + /// `pre` bias, and the `rq` rules under `half_up`, with every value by hand. + #[test] + fn conv_by_hand() { + let p = Params::Conv { cout: 1, kh: 1, kw: 1, sh: 1, sw: 1, ph: 0, pw: 0, groups: 1, w_bytes: 1, rq: rq(Round::HalfUp, BiasKind::Pre, vec![4], None, 1), w: vec![3, -2] }; + let g = one(CONV, vec![TensorRec::check(2, -5, 7)], TensorRec::derived(1), p); + let b = pass(&g, None).unwrap(); + let n = &b.nodes[0]; + // Terms: 3·[−5, 7] = [−15, 21] and −2·[−5, 7] = [−14, 10]. + assert_eq!(get(n, "conv.term"), iv(-15, 21)); + // A = [min(0, 4) − 15 − 14, max(0, 4) + 21 + 10]. + assert_eq!(get(n, "conv.acc"), iv(-29, 35)); + assert_eq!(get(n, "rq.t"), iv(-29, 35)); + // rq.p carries the addend 2^(s−1) = 1 on its upper end; rq.q does not. + assert_eq!(get(n, "rq.p"), iv(-29, 36)); + assert_eq!(get(n, "rq.q"), iv(-14, 18)); + assert_eq!(get(n, "rq.y"), iv(-14, 18)); + assert_eq!(n.results, vec![iv(-14, 18)]); + // K_c = ⌊(2^31 − 1) / 21⌋; operand widths: the input [−5, 7] and the weights [−2, 3]. + assert_eq!(n.k_c, Some(Some(x(102_261_126)))); + assert_eq!((n.a_bits.clone(), n.w_bits), (Some(vec![4]), Some(3))); + assert!(n.fits(Profile::Acc32) && !n.saturated); + } + + /// `rq.q` uses `P` without the addend, and `half_even` and a `post` bias apply per + /// channel, hulled. + #[test] + fn rq_rules_by_hand() { + // rescale over two channels: t = in + pre; m = [3, −1]; s = 2; half_even; then + // a post bias would be refused with a pre bias, so pre only here. + let p = Params::Rescale(Rq { round: Round::HalfEven, bias_kind: BiasKind::Pre, m_kind: 2, s_kind: 1, m_bytes: 8, b_bytes: 8, mult: vec![3, -1], shift: vec![2], bias: vec![1, -1] }); + let g = one(RESCALE, vec![TensorRec::check(2, -6, 6)], TensorRec::derived(2), p); + let n = &pass(&g, None).unwrap().nodes[0]; + // Channel 0: t = [−5, 7], P = [−15, 21], rq.p = [−15, 23], q = [R(−15), R(21)]: + // −15/4 = −3.75 → −4; 21/4 = 5.25 → 5. + // Channel 1: t = [−7, 5], P = [−5, 7], rq.p = [−5, 9], q: −5/4 → −1; 7/4 → 2. + assert_eq!(get(n, "rq.t"), iv(-7, 7)); + assert_eq!(get(n, "rq.p"), iv(-15, 23)); + assert_eq!(get(n, "rq.q"), iv(-4, 5)); + // Ties: R_half_even(−6, 2) = −2 (−1.5 → −2, even), R_half_even(10, 2) = 2. + let mut ar = Ar::default(); + assert_eq!(ar.round(x(-6), 2, Round::HalfEven), x(-2)); + assert_eq!(ar.round(x(10), 2, Round::HalfEven), x(2)); + assert_eq!(ar.round(x(-6), 2, Round::HalfUp), x(-1)); + assert_eq!(ar.round(x(-6), 2, Round::Floor), x(-2)); + assert!(!ar.hit); + } + + /// The residue rule of `conv_transpose`: one output position reads the taps of one + /// residue only, so the bound is the largest residue's sum, not every tap's. + #[test] + fn conv_transpose_residues_by_hand() { + // 3×3 kernel, stride 2, weights 1..9 row-major, input [0, 1], no bias. The + // residues' sums: (0,0) 1+3+7+9 = 20; (0,1) 2+8 = 10; (1,0) 4+6 = 10; (1,1) 5. + let w: Vec = (1..=9).collect(); + let p = Params::ConvT { cout: 1, kh: 3, kw: 3, sh: 2, sw: 2, ph: 0, pw: 0, oph: 0, opw: 0, w_bytes: 1, rq: Rq::plain(Round::Floor, 0), w }; + let g = one(CONV_TRANSPOSE, vec![TensorRec::check(1, 0, 1)], TensorRec::derived(1), p); + let n = &pass(&g, None).unwrap().nodes[0]; + assert_eq!(get(n, "convT.term"), iv(0, 9)); + assert_eq!(get(n, "convT.acc"), iv(0, 20)); + // A stride past the kernel: every tap is its own residue, and the empty + // residues' A(∅, b) = [min(0, b), max(0, b)] lies inside the others. + let p = Params::ConvT { cout: 1, kh: 2, kw: 1, sh: 5, sw: 5, ph: 0, pw: 0, oph: 0, opw: 0, w_bytes: 1, rq: rq(Round::Floor, BiasKind::Pre, vec![-3], None, 0), w: vec![4, -6] }; + let g = one(CONV_TRANSPOSE, vec![TensorRec::check(1, -1, 2)], TensorRec::derived(1), p); + let n = &pass(&g, None).unwrap().nodes[0]; + // Taps 4·[−1, 2] = [−4, 8] and −6·[−1, 2] = [−12, 6]; with b = −3: + // residue 0: [−3 − 4, 0 + 8] = [−7, 8]; residue 1: [−3 − 12, 0 + 6] = [−15, 6]. + assert_eq!(get(n, "convT.acc"), iv(-15, 8)); + } + + /// `igdn`: each term floored, the partial sums with `β` or without, and `r` taken + /// from the final norm, not from `igdn.N`. + #[test] + fn igdn_by_hand() { + let p = Params::Igdn { gf: 1, frac: 1, g_bytes: 4, gamma: vec![3], beta: vec![2] }; + let g = one(IGDN, vec![TensorRec::check(1, -4, 2)], TensorRec::derived(1), p); + let n = &pass(&g, None).unwrap().nodes[0]; + assert_eq!(get(n, "igdn.x2"), iv(0, 16)); + assert_eq!(get(n, "igdn.gx2"), iv(0, 48)); + assert_eq!(get(n, "igdn.term"), iv(0, 24)); + // igdn.N = A({[0, 24]}, 2) = [0, 26]; the final norm is [2, 26], so r = [1, 5]. + assert_eq!(get(n, "igdn.N"), iv(0, 26)); + assert_eq!(get(n, "igdn.r"), iv(1, 5)); + assert_eq!(get(n, "igdn.xr"), iv(-20, 10)); + assert_eq!(n.results, vec![iv(-10, 5)]); + assert_eq!(n.k_c, Some(Some(x(2_147_483_647 / 24)))); + } + + /// `leaky` floors the negative part; the parts are hulled. + #[test] + fn leaky_by_hand() { + let g = one(LEAKY, vec![TensorRec::check(1, -7, 5)], TensorRec::derived(1), Params::Leaky { a: 3, f: 1 }); + let n = &pass(&g, None).unwrap().nodes[0]; + // leaky.p = [−7, −1]·3 = [−21, −3]; ⌊−21/2⌋ = −11, ⌊−3/2⌋ = −2; then [0, 5]. + assert_eq!(get(n, "leaky.p"), iv(-21, -3)); + assert_eq!(n.results, vec![iv(-11, 5)]); + let g = one(LEAKY, vec![TensorRec::check(1, 2, 5)], TensorRec::derived(1), Params::Leaky { a: 3, f: 1 }); + let n = &pass(&g, None).unwrap().nodes[0]; + assert_eq!((get(n, "leaky.p"), n.results.clone()), (iv(0, 0), vec![iv(2, 5)])); + } + + /// The `exp_neg_q16` intervals are fixed (§7.3): `exp.t2` up to 88670² and `exp.c` + /// up to 23495·119970, whatever the input; `sigmoid` at −2^63 fails `acc64` through + /// `exp.negx`, and at −(2^63 − 1) it does not. + #[test] + fn exp_family_by_hand() { + let g = one(SIGMOID, vec![TensorRec::check(1, -i64::MAX, 5)], TensorRec::derived(1), Params::None); + let b = pass(&g, None).unwrap(); + let n = &b.nodes[0]; + assert_eq!(get(n, "exp.negx"), iv(0, i64::MAX as i128)); + assert_eq!(get(n, "exp.t2"), iv(43245 * 43245, 88670 * 88670)); + assert_eq!(get(n, "exp.c"), iv(0, 23495 * 119_970)); + assert_eq!(get(n, "sig.num"), iv(0, 65553 << 16)); + let nl = 45426 * ((i64::MAX as i128) / 45426); + assert_eq!(get(n, "exp.nl"), iv(0, nl)); + assert!(b.meets(&g, Profile::Acc64) && !b.meets(&g, Profile::Acc32)); + let g = one(SIGMOID, vec![TensorRec::check(1, i64::MIN, 5)], TensorRec::derived(1), Params::None); + let b = pass(&g, None).unwrap(); + let f = b.first_failure(&g, Profile::Acc64).unwrap(); + assert_eq!((f.at, f.miss.key.as_str(), f.miss.bits), (Where::Node, "exp.negx", Some(65))); + // elu(α) at the same edge, and its product α·(e − 2^16). + let g = one(ELU, vec![TensorRec::check(1, i64::MIN, 0)], TensorRec::derived(1), Params::Elu { alpha: 1 << 16 }); + let b = pass(&g, None).unwrap(); + assert_eq!(get(&b.nodes[0], "elu.p"), iv(-(1 << 32), 17 << 16)); + assert_eq!(b.first_failure(&g, Profile::Acc64).unwrap().miss.key, "exp.negx"); + } + + /// `layernorm_c`'s fixed bounds (lemma L1), by hand for `C = 3`, `[−10, 10]`, `ε = 1`. + #[test] + fn layernorm_by_hand() { + let p = Params::LayerNorm { eps: 1, g_bytes: 4, gamma: vec![1 << 16, -2, 3], beta: vec![0, 5, -5] }; + let g = one(LAYERNORM_C, vec![TensorRec::check(3, -10, 10)], TensorRec::derived(3), p); + let n = &pass(&g, None).unwrap().nodes[0]; + assert_eq!(get(n, "ln.S"), iv(-30, 30)); + assert_eq!(get(n, "ln.m"), iv(-31, 31)); + assert_eq!(get(n, "ln.d"), iv(-20, 20)); + assert_eq!(get(n, "ln.T"), iv(0, 1200)); + assert_eq!(get(n, "ln.v"), iv(1, 401)); + assert_eq!(get(n, "rsq.num"), iv(1 << 32, 1 << 32)); + assert_eq!(get(n, "ln.k"), iv(0, 1 << 32)); + // D = min(20·2^32, ⌈2·2^32·2 / 1⌉) = 2^34; N = min(20·2^16 + 1, 2·2^16·2 + 1). + assert_eq!(get(n, "ln.dk"), iv(-(1 << 34), 1 << 34)); + assert_eq!(get(n, "ln.n"), iv(-262_145, 262_145)); + // ng over γ ∈ {2^16, −2, 3}: [−262145·2^16, 262145·2^16]; out: ⌊ng/2^16⌋ + β. + assert_eq!(get(n, "ln.ng"), iv(-262_145 << 16, 262_145 << 16)); + assert_eq!(n.results, vec![iv(-262_145, 262_145)]); + } + + /// Saturation (§8.1): a value that passes 2^255 marks its node, which fits no + /// profile, and the pass goes on. + #[test] + fn saturation_marks_the_node() { + // mul(x, x) three times from [−2^62, 2^62]: 2^124, then 2^248, then 2^496. + let mut tensors = vec![TensorRec::check(1, -(1 << 62), 1 << 62)]; + let mut ops = Vec::new(); + for k in 0..3u32 { + tensors.push(TensorRec::derived(1)); + ops.push(Op { code: MUL, ins: vec![k, k], outs: vec![k + 1], p: Params::Mul(Rq::plain(Round::Floor, 0)) }); + } + let g = Graph { max_elems: CAP as u32, scalars: vec![], inputs: vec![input(0)], outputs: vec![3], tensors, ops }; + let b = pass(&g, None).unwrap(); + assert!(!b.nodes[0].saturated && !b.nodes[1].saturated && b.nodes[2].saturated); + assert_eq!(get(&b.nodes[1], "mul.p"), Iv::new(I512::pow2(248).neg(), I512::pow2(248))); + assert_eq!(get(&b.nodes[2], "mul.p"), Iv::new(I512::pow2(255).neg(), I512::pow2(255))); + assert_eq!(b.nodes[2].miss(Profile::Acc64).unwrap().key, "saturated"); + // The first failure is the first node that fails, not the saturated one. + let f = b.first_failure(&g, Profile::Acc64).unwrap(); + assert_eq!((f.index, f.miss.key.as_str(), f.miss.bits), (0, "mul.p", Some(126))); + // igdn.x2 on an input at ±2^255 forms 2^510 before saturating it. + let mut ar = Ar::default(); + let p = I512::pow2(255); + assert_eq!(ar.mul(p, p), p); + assert!(ar.hit); + } + + /// The load-step-8 refusals of the pass: an empty `check` intersection and a + /// `lut16` input range past `[−32767, 32767]`. + #[test] + fn the_pass_refuses() { + let g = one(RELU, vec![TensorRec::check(1, -5, 5)], TensorRec::check(1, -9, -1), Params::None); + assert_eq!(pass(&g, None).unwrap_err(), Refusal::new(Code::ModelMismatch, Site::Load(8))); + let mut t = vec![0i16; 65536]; + t[1] = 7; + for (lo, hi, ok) in [(-32767, 32767, true), (-32768, 0, false), (0, 32768, false)] { + let g = one(LUT16, vec![TensorRec::check(1, lo, hi)], TensorRec::derived(1), Params::Lut16 { e_in: -128, e_out: -128, t: t.clone() }); + assert_eq!(pass(&g, None).is_ok(), ok, "[{lo}, {hi}]"); + } + } + + /// First failure under `acc32`: an interval first (most bits, then the smallest + /// key), then the first parameter condition, then a `check` output. + #[test] + fn first_failure_order() { + // Every parameter condition of an rq fails; y = 2^31 fails too, and `out.0` + // wins the tie with `rq.y` (33 bits each) by key order. + let p = Params::Rescale(rq(Round::Floor, BiasKind::Post, vec![1 << 31], Some(vec![1 << 31]), 64)); + let g = one(RESCALE, vec![TensorRec::check(1, 0, 0)], TensorRec::derived(1), p); + let b = pass(&g, None).unwrap(); + let n = &b.nodes[0]; + assert_eq!(n.params32, vec!["rq.mult", "rq.shift", "rq.post_bias"]); + assert_eq!(n.miss(Profile::Acc32).unwrap(), Miss { key: "out.0".into(), bits: Some(33) }); + // A post bias of 2^31 with q in [−2^31, −1]: every interval fits i32, and only + // the parameter condition fails. + assert!(n.fits(Profile::Acc64)); + let p = Params::Rescale(rq(Round::Floor, BiasKind::Post, vec![1 << 31], None, 0)); + let g = one(RESCALE, vec![TensorRec::check(1, -(1 << 31), -1)], TensorRec::check(1, -5, 5), p); + let n = &pass(&g, None).unwrap().nodes[0]; + assert_eq!(n.miss(Profile::Acc32).unwrap(), Miss { key: "rq.post_bias".into(), bits: None }); + let g = one(RELU, vec![TensorRec::check(1, -5, 5)], TensorRec::check(1, 0, 4), Params::None); + let n = &pass(&g, None).unwrap().nodes[0]; + assert_eq!(n.miss(Profile::Acc32).unwrap(), Miss { key: "policy.check".into(), bits: None }); + // An input or a scalar past i32 is the failure before any node. + let mut g = one(RELU, vec![TensorRec::check(1, -5, 1 << 31)], TensorRec::derived(1), Params::None); + g.scalars.push(ScalarRec { lo: 0, hi: 1 << 40 }); + let f = pass(&g, None).unwrap().first_failure(&g, Profile::Acc32).unwrap(); + assert_eq!((f.at, f.index, f.miss.bits), (Where::Input, 0, Some(33))); + g.tensors[0] = TensorRec::check(1, -5, 5); + let f = pass(&g, None).unwrap().first_failure(&g, Profile::Acc32).unwrap(); + assert_eq!((f.at, f.index, f.miss.bits), (Where::Scalar, 0, Some(42))); + } + + /// The admissible range (§8.4) of a convolution's input with weight 2 under + /// `acc32`: `2X ≤ 2^31 − 1`. + #[test] + fn admissible_by_hand() { + let p = Params::Conv { cout: 1, kh: 1, kw: 1, sh: 1, sw: 1, ph: 0, pw: 0, groups: 1, w_bytes: 1, rq: Rq::plain(Round::Floor, 0), w: vec![2] }; + let g = one(CONV, vec![TensorRec::check(1, -5, 5)], TensorRec::derived(1), p); + let b = pass(&g, None).unwrap(); + assert_eq!(admissible(&g, None, &b, 0, Profile::Acc32), Some(iv(-1_073_741_823, 1_073_741_823))); + assert_eq!(admissible(&g, None, &b, 0, Profile::Acc64), Some(iv(-((1 << 62) - 1), (1 << 62) - 1))); + // A tensor no operator reads: every X holds, and the range is i64's. + assert_eq!(admissible(&g, None, &b, 1, Profile::Acc32), Some(iv(-(1 << 63), i64::MAX as i128))); + // sigmoid's fixed intervals fail acc32 whatever its input. + let g = one(SIGMOID, vec![TensorRec::check(1, -5, 5)], TensorRec::derived(1), Params::None); + let b = pass(&g, None).unwrap(); + assert_eq!(admissible(&g, None, &b, 0, Profile::Acc32), None); + } + + /// `gram` and `apply`: the corner hull of two run-time intervals, summed over the + /// largest `H·W` the declared sizes allow (`gram`) or over `d` (`apply`). + #[test] + fn contractions_by_hand() { + let mut g = one(GRAM, vec![TensorRec::check(1, -2, 3), TensorRec::check(1, -1, 4)], TensorRec::derived(1), Params::Gram { groups: 1, rq: Rq::plain(Round::HalfUp, 1) }); + for i in &mut g.inputs { + (i.max_h, i.max_w) = (2, 3); + } + let sizes = crate::plan::load_plan(&g).unwrap(); + let n = &pass(&g, sizes.as_deref()).unwrap().nodes[0]; + // Corners {2, −8, −3, 12}; L = 2·3 = 6. + assert_eq!(get(n, "gram.term"), iv(-8, 12)); + assert_eq!(get(n, "gram.acc"), iv(-48, 72)); + assert_eq!(get(n, "rq.p"), iv(-48, 73)); + assert_eq!(get(n, "rq.q"), iv(-24, 36)); + assert_eq!(n.npu_flags, Vec::<&str>::new()); + let g = one(APPLY, vec![TensorRec::check(2, -3, 3), TensorRec::check(2, 0, 5)], TensorRec::derived(2), Params::Apply { groups: 1, rq: Rq::plain(Round::Floor, 0) }); + let n = &pass(&g, None).unwrap().nodes[0]; + // d = 2 / 1; corners {0, −15, 0, 15}. + assert_eq!(get(n, "apply.term"), iv(-15, 15)); + assert_eq!(get(n, "apply.acc"), iv(-30, 30)); + assert_eq!(n.results, vec![iv(-30, 30)]); + } + + /// The elementwise and movement rules: each output's interval from its inputs'. + #[test] + fn elementwise_and_movement_by_hand() { + let two = vec![TensorRec::check(1, -1, 2), TensorRec::check(1, 5, 9)]; + let r = |code: u8, ins: Vec, out: TensorRec, p: Params| pass(&one(code, ins, out, p), None).unwrap().nodes[0].results.clone(); + assert_eq!(r(ADD, two.clone(), TensorRec::derived(1), Params::None), vec![iv(4, 11)]); + assert_eq!(r(CONCAT, two.clone(), TensorRec::derived(2), Params::None), vec![iv(-1, 9)]); + assert_eq!(r(CROP_TO, two, TensorRec::derived(1), Params::None), vec![iv(-1, 2)]); + assert_eq!(r(CHUNK_ADD, vec![TensorRec::check(2, -1, 2)], TensorRec::derived(1), Params::None), vec![iv(-2, 4)]); + assert_eq!(r(ABS, vec![TensorRec::check(1, -7, 3)], TensorRec::derived(1), Params::None), vec![iv(0, 7)]); + assert_eq!(r(ABS, vec![TensorRec::check(1, -7, -3)], TensorRec::derived(1), Params::None), vec![iv(3, 7)]); + assert_eq!(r(RELU, vec![TensorRec::check(1, -7, -3)], TensorRec::derived(1), Params::None), vec![iv(0, 0)]); + assert_eq!(r(CLAMP, vec![TensorRec::check(1, -7, 30)], TensorRec::derived(1), Params::Clamp { lo: 0, hi: 9 }), vec![iv(0, 9)]); + assert_eq!(r(FILL, vec![TensorRec::check(1, -7, 30)], TensorRec::derived(3), Params::Fill { kind: 0, value: -4 }), vec![iv(-4, -4)]); + let mut g = one(FILL, vec![TensorRec::check(1, -7, 30)], TensorRec::derived(1), Params::Fill { kind: 1, value: 0 }); + g.scalars.push(ScalarRec { lo: 3, hi: 7 }); + assert_eq!(pass(&g, None).unwrap().nodes[0].results, vec![iv(3, 7)]); + // A clamp policy on the output: [clamp(a), clamp(b)] after the producer result. + let g = one(ADD, vec![TensorRec::check(1, -1, 2), TensorRec::check(1, 5, 9)], TensorRec::clamp(1, 0, 6), Params::None); + let n = &pass(&g, None).unwrap().nodes[0]; + assert_eq!((n.results[0], n.outs[0].2), (iv(4, 11), iv(4, 6))); + } + + /// The certificate's canonical bytes for a one-operator graph, written out by hand. + #[test] + fn certificate_bytes() { + let g = one(RELU, vec![TensorRec::check(1, -5, 5)], TensorRec::derived(1), Params::None); + let bytes = g.to_bytes(); + let c = certify(None, "whg1", None, &[("g", &bytes)]).unwrap(); + let sha = json::hex(&sha256(&bytes)); + let want = format!( + "{{\"capability\":null,\"certificate\":\"wai-ops/1 bounds\",\"graphs\":[{{\"graph_sha256\":\"{sha}\",\"inputs\":[{{\"hi\":\"5\",\"kind\":\"data\",\"lo\":\"-5\",\"max_h\":\"0\",\"max_w\":\"0\",\"policy\":\"check\",\"tensor\":\"0\"}}],\"name\":\"g\",\"nodes\":[{{\"acc32_params\":[],\"fits\":[\"acc32\",\"acc64\"],\"index\":\"0\",\"intermediates\":{{}},\"npu_flags\":[],\"op\":\"relu\",\"out\":[{{\"bits\":\"4\",\"hi\":\"5\",\"lo\":\"0\",\"policy\":\"derived\",\"result\":{{\"bits\":\"4\",\"hi\":\"5\",\"lo\":\"0\"}},\"tensor\":\"1\"}}],\"saturated\":false}}],\"scalars\":[]}}],\"lowering\":\"whg1\",\"set_sha256\":null,\"verdict\":{{\"acc32\":true,\"acc64\":true,\"npu\":true,\"npu_flags\":[],\"npu_reasons\":[]}}}}" + ); + assert_eq!(c.to_json(), want); + } +} diff --git a/wai/wai-ops/src/generate/build.rs b/wai/wai-ops/src/generate/build.rs index 5f9cb079a..173eed50b 100644 --- a/wai/wai-ops/src/generate/build.rs +++ b/wai/wai-ops/src/generate/build.rs @@ -4,7 +4,7 @@ use alloc::string::String; use alloc::vec; use alloc::vec::Vec; -use super::tag; +use crate::bounds::Profile; use crate::graph::{self, CAP, Graph, InputRec, Op, Params, ScalarRec, TensorRec}; use crate::interp::Tensor; use crate::json::{self, C, hex}; @@ -45,43 +45,27 @@ pub fn one_op(code: u8, ins: Vec, outs: Vec, p: Params, scalars: Graph { max_elems: CAP as u32, scalars, inputs, outputs: (n..n + no).collect(), tensors, ops: vec![op] } } -/// The profiles a graph's vector is tagged with: both when its load refuses (steps -/// 1–7 do not depend on a profile); otherwise those its verdict meets, or `None` when -/// it meets neither (a load-refusal vector of D2b, not written here). -pub fn profiles(bytes: &[u8]) -> Option> { - let g = match graph::Graph::parse(bytes) { - Ok(g) => g, - Err(_) => return Some(vec!["acc32", "acc64"]), - }; - let sizes = match crate::plan::load_plan(&g) { - Ok(s) => s, - Err(_) => return Some(vec!["acc32", "acc64"]), - }; - let v = tag::verdict(&g, sizes.as_deref()); - match (v.acc32, v.acc64) { - (true, true) => Some(vec!["acc32", "acc64"]), - (false, true) => Some(vec!["acc64"]), - _ => None, - } -} - -/// The vector line for a graph and its decodes, with `load` and every `expect` -/// computed by [`vectors::graph_line`]; `None` when the graph meets no profile. -pub fn line(id: &str, bytes: &[u8], decodes: &[Decode]) -> Option { - let prof = profiles(bytes)?; +/// The vector line for a graph and its decodes, with `load`, `profiles` and every +/// `expect` computed by [`vectors::graph_line`]: a graph whose load is refused, at +/// any step of §10.5 including step 8, keeps no decodes and lists both profiles. +pub fn line(id: &str, bytes: &[u8], decodes: &[Decode]) -> String { let ds: Vec = decodes .iter() .map(|d| C::obj(vec![("inputs", C::Arr(d.inputs.iter().map(vectors::tensor_c).collect())), ("scalars", C::ints(d.scalars.iter().map(|&s| s as i128)))])) .collect(); - let c = C::obj(vec![ - ("decodes", C::Arr(ds)), - ("graph", C::Str(hex(bytes))), - ("id", C::s(id)), - ("profiles", C::Arr(prof.iter().map(|p| C::s(p)).collect())), - ]); - let v = json::parse(json::to_string(&c).as_bytes()).ok()?; - let out = vectors::graph_line(&v).ok()?; - Some(json::to_string(&out)) + let c = C::obj(vec![("decodes", C::Arr(ds)), ("graph", C::Str(hex(bytes))), ("id", C::s(id)), ("profiles", C::Arr(vec![]))]); + let v = json::parse(json::to_string(&c).as_bytes()).expect("a canonical line parses"); + json::to_string(&vectors::graph_line(&v).expect("a generated line recomputes")) +} + +/// Whether a random case is kept: unless load step 8 is what refuses its graph. A +/// graph refused at steps 1–7 is a load-refusal vector like any other; one that only +/// step 8 refuses meets no profile, and a random case is drawn again in its place. +pub fn random_keeps(bytes: &[u8]) -> bool { + match graph::load(bytes, Profile::Acc64) { + Ok(_) => true, + Err(r) => r.at != crate::code::Site::Load(8), + } } /// A file of lines. diff --git a/wai/wai-ops/src/generate/graphs.rs b/wai/wai-ops/src/generate/graphs.rs index b50936f24..2a7bdcfb2 100644 --- a/wai/wai-ops/src/generate/graphs.rs +++ b/wai/wai-ops/src/generate/graphs.rs @@ -39,9 +39,7 @@ impl G { fn emit(&mut self, class: &str, b: &[u8], d: Vec) { let id = format!("{}/{}/{}", self.name, class, self.n); self.n += 1; - let l = line(&id, b, &d); - assert!(l.is_some(), "{id}: a graph vector meets no profile"); - self.file.push(l); + self.file.push(Some(line(&id, b, &d))); } } @@ -109,7 +107,7 @@ fn phase() -> File { let d = vec![Decode::new(vec![x.clone()], vec![ho as i64, wo as i64])]; // The two outputs agree, or the phase form is not what §9.3 says. let b = gr.to_bytes(); - let gl = crate::graph::load(&b).expect("phase graph loads"); + let gl = crate::graph::load(&b, crate::bounds::Profile::Acc64).expect("phase graph loads"); match run(&gl, &[x], &[ho as i64, wo as i64], &mut Sequence::new()) { Ok(outs) => assert_eq!(outs[0], outs[1], "the phase form differs from conv_transpose"), Err(e) => panic!("phase graph refused: {e:?}"), @@ -382,6 +380,24 @@ fn load_refusals() -> File { ops: vec![op(CROP, vec![0], vec![1], Params::Crop { y0: Operand::Scalar(0), x0: Operand::Const(0), h: Operand::Const(4), w: Operand::Const(1) })], }; g.emit("crop_plan", &gr.to_bytes(), vec![Decode::new(vec![Tensor::filled(1, 4, 4, 2)], vec![1]), Decode::new(vec![Tensor::filled(1, 4, 4, 2)], vec![3])]); + // Step 8 (§8.1, §8.6): the base graph with its relu's output checked against a + // range its producer cannot give, refused under both profiles; against one that + // meets the producer's interval at a single value, which loads under acc64 only + // (a check inside the graph); and with its convolution's weight raised until + // `conv.acc` passes i64, which no profile meets. + let mut gr = load_base(); + gr.tensors[2] = chk(3, -9, -1); + g.emit("step8", &gr.to_bytes(), vec![]); + let mut gr = load_base(); + gr.tensors[2] = chk(3, -9, 0); + g.emit("step8", &gr.to_bytes(), vec![Decode::new(vec![Tensor::new(2, 1, 2, vec![-9, 9, 3, -3])], vec![0]), Decode::new(vec![Tensor::new(2, 1, 2, vec![0, -1, 0, 0])], vec![0])]); + let mut gr = load_base(); + gr.tensors[0] = chk(2, i64::MIN, i64::MAX); + if let Params::Conv { w, w_bytes, .. } = &mut gr.ops[0].p { + *w = vec![1, 1, 1, 1, 1, 1]; + *w_bytes = 1; + } + g.emit("step8", &gr.to_bytes(), vec![]); g.file } diff --git a/wai/wai-ops/src/generate/mod.rs b/wai/wai-ops/src/generate/mod.rs index 520170871..a608f8cf8 100644 --- a/wai/wai-ops/src/generate/mod.rs +++ b/wai/wai-ops/src/generate/mod.rs @@ -7,8 +7,8 @@ //! the graph bytes and the inputs, and every lowered graph from its set, and must //! write the same bytes. //! -//! It runs the interpreter, so it needs the `uncertified` feature, as every decode -//! does before the certifier exists. +//! Every graph vector's `load` and `profiles` come from load step 8, the certifier +//! of [`crate::bounds`], and every expectation from the interpreter. use alloc::format; use alloc::string::String; @@ -20,7 +20,6 @@ pub mod ops; pub mod rng; pub mod sets; pub mod stages; -pub mod tag; /// Every file of `ops-conformance/` the generator writes, by its path below /// `ops-conformance/`, with the count of cases dropped because they met no profile. @@ -54,6 +53,8 @@ pub fn all(read: &dyn Fn(&str) -> Option>) -> Result<(Vec<(String, Vec Option>) -> Result<(Vec<(String, Vec "lower_int_synth", @@ -80,5 +83,27 @@ pub fn all(read: &dyn Fn(&str) -> Option>) -> Result<(Vec<(String, Vec = l.roles.iter().map(|(r, _)| *r).collect(); + for (r, g) in &l.roles { + files.push((format!("certificates/{}/{digest}/{r}.whg1", s.capability), g.to_bytes())); + } + let cert = sets::certificate(&s, &digest, &l)?; + if cert.verdict().meets(claim) { + return Err(format!("{}: the falsification set meets {}", s.name, claim.as_str())); + } + files.push((format!("certificates/{}/{digest}.json", s.capability), cert.to_json().into_bytes())); + fals.push(sets::falsification_entry(&s, &digest, &roles, claim)); + } + files.push((String::from("certificates/falsification.json"), sets::falsification_json(fals))); Ok((files, dropped)) } diff --git a/wai/wai-ops/src/generate/ops.rs b/wai/wai-ops/src/generate/ops.rs index 18841e009..ffdabcbe5 100644 --- a/wai/wai-ops/src/generate/ops.rs +++ b/wai/wai-ops/src/generate/ops.rs @@ -5,7 +5,7 @@ use alloc::string::String; use alloc::vec; use alloc::vec::Vec; -use super::build::{Decode, File, In, line, one_op}; +use super::build::{Decode, File, In, line, one_op, random_keeps}; use super::rng::Rng; use crate::graph::{BiasKind, Graph, Operand, Params, Round, Rq, ScalarRec, TensorRec, opcode::*, smallest_width}; use crate::interp::Tensor; @@ -114,16 +114,16 @@ impl Gen { fn new(name: &'static str) -> Gen { Gen { rng: Rng::named(name), file: File::default(), name, n: 0 } } - /// Write one vector; returns whether it was kept. - fn emit(&mut self, class: &str, g: &Graph, d: Vec) -> bool { + /// Write one vector: a graph that loads, with its decodes, or one whose load is + /// refused (load step 8 included), with none. + fn emit(&mut self, class: &str, g: &Graph, d: Vec) { let id = format!("{}/{}/{}", self.name, class, self.n); self.n += 1; let l = line(&id, &g.to_bytes(), &d); - let kept = l.is_some(); - self.file.push(l); - kept + self.file.push(Some(l)); } - /// Write `count` random vectors from `f`, retrying cases that meet no profile. + /// Write `count` random vectors from `f`, retrying cases whose graph meets no + /// profile. fn random(&mut self, count: usize, mut f: impl FnMut(&mut Rng) -> (Graph, Vec)) { let mut made = 0; let mut tries = 0; @@ -131,7 +131,9 @@ impl Gen { tries += 1; let (g, d) = f(&mut self.rng); let id = format!("{}/random/{}", self.name, self.n); - if let Some(l) = line(&id, &g.to_bytes(), &d) { + let b = g.to_bytes(); + if random_keeps(&b) { + let l = line(&id, &b, &d); self.n += 1; self.file.lines.push(l); made += 1; @@ -209,9 +211,105 @@ fn file(code: u8, name: &'static str) -> File { APPLY => apply(&mut g), _ => {} } + step8(&mut g, code); g.file } +// ------------------------------------------------------------------ load step 8 + +/// An `RQ` with one multiplier, one shift and one bias of the given placement. +fn rq1(round: Round, m: Option, s: u8, bias: BiasKind, b: i64) -> Rq { + let (m_kind, m_bytes, mult) = match m { + None => (0, 0, vec![]), + Some(v) => (1, smallest_width(&[v], &[4, 8]), vec![v]), + }; + let (b_bytes, bv) = if bias == BiasKind::None { (0, vec![]) } else { (smallest_width(&[b], &[4, 8]), vec![b]) }; + Rq { round, bias_kind: bias, m_kind, s_kind: 1, m_bytes, b_bytes, mult, shift: vec![s], bias: bv } +} + +/// The vectors whose outcome only the verdict decides (§14.1 item 6), appended to each +/// operator's file after its other cases: +/// - `sigmoid` and `elu` on an input range that reaches −2^63, which fails `acc64` +/// through `exp.negx` and is refused at load; +/// - an `rq` whose `q` passes 64 bits while `y` fits (with a `post` bias), refused at +/// load under `acc64`; for the operators without a bias, `q` and `y` pass together; +/// - `l2norm` with `ε = 2^64 − 1` (`layernorm_c`'s is among its own cases); +/// - for each key of §7.2's table, a graph that fails `acc32` by that parameter +/// condition alone: every interval fits i32, so it loads under `acc64` only; +/// - `lut16` on an input range that reaches ±32768, refused at load (§5.6). +fn step8(g: &mut Gen, code: u8) { + let x1 = |v: Vec| Tensor::new(1, 1, v.len() as u32, v); + let unary = |g: &mut Gen, class: &str, lo: i64, hi: i64, p: Params, d: Vec>| { + let gr = one_op(code, vec![inp(chk(1, lo, hi), 0, 0)], vec![der(1)], p, vec![]); + g.emit(class, &gr, d.into_iter().map(|v| Decode::new(vec![x1(v)], vec![])).collect()); + }; + const P61: i64 = 1 << 61; + let conv1 = |w: i64, rq: Rq| Params::Conv { cout: 1, kh: 1, kw: 1, sh: 1, sw: 1, ph: 0, pw: 0, groups: 1, w_bytes: smallest_width(&[w], &[1, 2, 4, 8]), rq, w: vec![w] }; + let convt1 = |w: i64, rq: Rq| Params::ConvT { cout: 1, kh: 1, kw: 1, sh: 1, sw: 1, ph: 0, pw: 0, oph: 0, opw: 0, w_bytes: smallest_width(&[w], &[1, 2, 4, 8]), rq, w: vec![w] }; + match code { + SIGMOID => { + unary(g, "step8", i64::MIN, 0, Params::None, vec![]); + unary(g, "step8", i64::MIN, i64::MAX, Params::None, vec![]); + } + ELU => { + for alpha in [1i64 << 16, 1] { + unary(g, "step8", i64::MIN, 0, Params::Elu { alpha }, vec![]); + } + } + RESCALE => { + // t = 2^61, m = 4: q = 2^63 passes i64, y = 2^63 − 1 fits; one less fits. + let q = |v| rq1(Round::Floor, Some(4), 0, BiasKind::Post, v); + unary(g, "step8_q", P61, P61, Params::Rescale(q(-1)), vec![]); + unary(g, "step8_q", P61 - 1, P61 - 1, Params::Rescale(q(-1)), vec![vec![P61 - 1]]); + // One per key of the rq rows of §7.2. + unary(g, "acc32_param", 0, 3, Params::Rescale(rq1(Round::Floor, Some(1 << 31), 31, BiasKind::None, 0)), vec![vec![0, 1, 2, 3]]); + unary(g, "acc32_param", 0, 3, Params::Rescale(rq1(Round::Floor, None, 64, BiasKind::None, 0)), vec![vec![0, 3]]); + unary(g, "acc32_param", -(1 << 31), -1, Params::Rescale(rq1(Round::Floor, None, 0, BiasKind::Post, 1 << 31)), vec![vec![-(1 << 31), -1]]); + } + CONV | CONV_TRANSPOSE => { + let mk = |w, rq| if code == CONV { conv1(w, rq) } else { convt1(w, rq) }; + let q = rq1(Round::Floor, Some(4), 0, BiasKind::Post, -1); + unary(g, "step8_q", P61, P61, mk(1, q.clone()), vec![]); + unary(g, "step8_q", 0, P61 - 1, mk(1, q), vec![vec![0, P61 - 1]]); + unary(g, "acc32_param", -1, 0, mk(1 << 31, Rq::plain(Round::Floor, 0)), vec![vec![-1, 0]]); + } + MUL => { + let rq = rq1(Round::Floor, Some(2), 0, BiasKind::None, 0); + let gr = one_op(MUL, vec![inp(chk(1, 1 << 31, 1 << 31), 0, 0), inp(chk(1, 1 << 31, 1 << 31), 0, 0)], vec![der(1)], Params::Mul(rq), vec![]); + g.emit("step8_q", &gr, vec![]); + } + CHSCALE => { + let sc = vec![ScalarRec { lo: 0, hi: 0 }]; + let ch = |m: i64, shift: u8| Params::Chscale { scalar: 0, n_rows: 1, round: Round::Floor, m_bytes: smallest_width(&[m], &[4, 8]), shift, m: vec![m] }; + let gr = one_op(CHSCALE, vec![inp(chk(1, 1 << 62, 1 << 62), 0, 0)], vec![der(1)], ch(2, 0), sc.clone()); + g.emit("step8_q", &gr, vec![]); + let gr = one_op(CHSCALE, vec![inp(chk(1, -1, 0), 0, 0)], vec![der(1)], ch(1 << 31, 31), sc.clone()); + g.emit("acc32_param", &gr, vec![Decode::new(vec![x1(vec![-1, 0])], vec![0])]); + let gr = one_op(CHSCALE, vec![inp(chk(1, 0, 5), 0, 0)], vec![der(1)], ch(1, 64), sc); + g.emit("acc32_param", &gr, vec![Decode::new(vec![x1(vec![0, 5])], vec![0])]); + } + IGDN => { + let ig = |gf: u32, gamma: i64| Params::Igdn { gf, frac: 0, g_bytes: smallest_width(&[gamma], &[4, 8]), gamma: vec![gamma], beta: vec![1] }; + unary(g, "acc32_param", 0, 1, ig(31, 1 << 31), vec![vec![0, 1]]); + unary(g, "acc32_param", 0, 1, ig(64, 1), vec![vec![0, 1]]); + } + LEAKY => unary(g, "acc32_param", -1, 5, Params::Leaky { a: 1 << 31, f: 31 }, vec![vec![-1, 0, 5]]), + L2NORM => { + let gr = one_op(L2NORM, vec![inp(chk(1, -5, 5), 2, 2)], vec![der(1)], Params::L2norm { eps: u64::MAX }, vec![]); + g.emit("eps", &gr, vec![Decode::new(vec![Tensor::new(1, 2, 2, vec![-5, 5, 1, 0])], vec![])]); + } + LUT16 => { + let mut t = vec![1i16; 65536]; + t[0] = 0; + for (lo, hi) in [(-32768, 0), (0, 32768)] { + let gr = one_op(LUT16, vec![inp(chk(1, lo, hi), 0, 0)], vec![der(1)], Params::Lut16 { e_in: -128, e_out: -128, t: t.clone() }, vec![]); + g.emit("step8", &gr, vec![]); + } + } + _ => {} + } +} + // ------------------------------------------------------------------ conv fn conv_params(r: &mut Rng, cin: u32) -> (Params, u32, u32, u32, u32, u32) { diff --git a/wai/wai-ops/src/generate/sets.rs b/wai/wai-ops/src/generate/sets.rs index 8e1ec8dfe..15881d6fa 100644 --- a/wai/wai-ops/src/generate/sets.rs +++ b/wai/wai-ops/src/generate/sets.rs @@ -8,6 +8,7 @@ use alloc::vec::Vec; use super::rng::Rng; use crate::json::{self, C, hex}; +use crate::bounds::{self, Certificate, Profile}; use crate::lower::{self, Lowered}; use crate::sha256::sha256; @@ -122,6 +123,56 @@ pub fn synthetic() -> Vec<(Set, Vec<(&'static str, Vec)>)> { v } +/// The two sets of §14.3 that a certificate must reject, each with the profile it is +/// checked against: an `int_synth` set whose accumulator passes i64 by one unit, and +/// one whose pin claims `acc32` and whose accumulator passes i32 by one unit. Each is +/// one unit past a set that meets the profile, which is the set with the bias or the +/// weight named below one smaller. +pub fn falsification() -> Vec<(Set, Vec<(&'static str, Vec)>, Profile)> { + let base = |n: &str| format!("ops-conformance/sets/{n}/int_synth.json"); + let layer = |i: usize, o: usize, w: &[i64], b: &[i64], shift: u32, relu: bool| -> String { + let mut s = format!("{{\"in_ch\":{i},\"out_ch\":{o},\"k\":1,\"stride\":1,\"pad\":0,\"weight\":{},\"bias\":{},\"shift\":{shift}", ints(w), ints(b)); + if relu { + s.push_str(",\"relu\":true"); + } + s.push('}'); + s + }; + let doc = |layers: &[String]| -> Vec { + let mut s = String::from("{\"layers\":["); + s.push_str(&layers.join(",")); + s.push_str("]}\n"); + s.into_bytes() + }; + // 127 · 331720249 · 218934409 = 2^63 − 1. Layer 1 maps [−128, 127] onto + // [0, 127·331720249] (ReLU); layer 2's channel 0 then sums to 2^63 − 1 plus its + // bias of 1: `convT.acc` reaches 2^63, one past i64. With a bias of 0 it fits. + let overflow = doc(&[layer(1, 1, &[331_720_249], &[0], 0, true), layer(1, 3, &[218_934_409, 0, 0], &[1, 0, 0], 0, false)]); + // Layer 1 maps [−128, 127] onto [−1, 1] in each of two channels (shift 8, bias + // 129); layer 2's channel 0 sums both with weight 2^30: `convT.acc` reaches 2^31, + // one past i32. With one of those weights 2^30 − 1 it fits. + let claim = doc(&[layer(1, 2, &[1, 1], &[129, 129], 8, false), layer(2, 3, &[1 << 30, 0, 0, 1 << 30, 0, 0], &[0, 0, 0], 0, false)]); + vec![ + ( + Set { name: "overflow_acc64", capability: "wai.neural.int_synth", lowering: "int_synth/1", members: vec![("int_synth.json", base("overflow_acc64"))], c: None, note: "fails acc64 by one unit (section 14.3)" }, + vec![("int_synth.json", overflow)], + Profile::Acc64, + ), + ( + Set { name: "claim_acc32", capability: "wai.neural.int_synth", lowering: "int_synth/1", members: vec![("int_synth.json", base("claim_acc32"))], c: None, note: "its pin claims acc32, which it fails by one weight (section 14.3)" }, + vec![("int_synth.json", claim)], + Profile::Acc32, + ), + ] +} + +/// The bounds certificate (§8.5) of a set's lowered graphs. +pub fn certificate(s: &Set, digest: &str, l: &Lowered) -> Result { + let bytes: Vec<(&str, Vec)> = l.roles.iter().map(|(r, g)| (*r, g.to_bytes())).collect(); + let refs: Vec<(&str, &[u8])> = bytes.iter().map(|(r, b)| (*r, b.as_slice())).collect(); + bounds::certify(Some(s.capability), s.lowering, Some(digest), &refs).map_err(|e| format!("{}: {} cannot be certified ({:?})", s.name, e.name, e.refusal)) +} + /// The set's digest (SPEC §3.1): one file's SHA-256, or its listing's. pub fn set_digest(members: &[(&str, Vec)]) -> String { if members.len() == 1 { @@ -448,6 +499,26 @@ fn jpegai_bundle(r: &mut Rng) -> (Vec, Vec, Vec) { /// Write the index (`certificates/index.json`): pretty enough to read, and /// canonical in its member order. +/// The entry of a falsification set: an index entry with the profile it is checked +/// against, `claim`, whose verdict it fails. +pub fn falsification_entry(s: &Set, digest: &str, roles: &[&str], claim: Profile) -> C { + match index_entry(s, digest, roles, true) { + C::Obj(mut m) => { + m.push((String::from("claim"), C::s(claim.as_str()))); + C::Obj(m) + } + c => c, + } +} + +/// `certificates/falsification.json`. +pub fn falsification_json(entries: Vec) -> Vec { + let c = C::obj(vec![("format", C::s("wai-ops-falsification/1")), ("sets", C::Arr(entries))]); + let mut s = json::to_string(&c); + s.push('\n'); + s.into_bytes() +} + pub fn index_json(entries: Vec) -> Vec { let c = C::obj(vec![("format", C::s("wai-ops-lowered/1")), ("sets", C::Arr(entries))]); let mut s = json::to_string(&c); diff --git a/wai/wai-ops/src/generate/tag.rs b/wai/wai-ops/src/generate/tag.rs deleted file mode 100644 index 89e2a3f61..000000000 --- a/wai/wai-ops/src/generate/tag.rs +++ /dev/null @@ -1,511 +0,0 @@ -//! The profiles a generated graph meets (§7, §8.3), for the `profiles` member of its -//! vector. -//! -//! This is the generator's own tagger, not the certifier: it applies the bound rules -//! of §8.3 and the classes and parameter conditions of §7 to the graphs the generator -//! writes, in `i128` with every step checked. A value that leaves `i128` lies outside -//! every class width of both profiles, so treating it as a failure gives the same -//! verdict as saturating it (§8.1). The certifier (D2b) computes the same verdicts -//! from the text, and must agree with every tag written here. -//! -//! What a node fits follows §8.5: its intermediates and its producer results. A -//! tensor's interval after a `clamp` policy is not classed by that rule, although -//! §7.1 calls every tensor element class `tensor`; no vector here depends on the -//! difference. - -use alloc::vec; -use alloc::vec::Vec; - -use crate::graph::{BiasKind, Graph, Operand, Params, Policy, Round, Rq, opcode::*}; -use crate::interp::round; - -/// An interval. -type Iv = (i128, i128); - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Verdict { - pub acc32: bool, - pub acc64: bool, -} - -/// Widths of a class under each profile: (acc32, acc64), in bits. -#[derive(Clone, Copy)] -enum Class { - Tensor, - Acc, - Wide, - Product, -} - -fn widths(c: Class) -> (u32, u32) { - match c { - Class::Tensor | Class::Acc => (32, 64), - Class::Wide => (32, 128), - Class::Product => (64, 128), - } -} - -fn fits(v: i128, n: u32) -> bool { - if n >= 128 { - return true; - } - let lim = 1i128 << (n - 1); - -lim <= v && v < lim -} - -struct Acc { - a32: bool, - a64: bool, - dead: bool, -} - -impl Acc { - fn class(&mut self, iv: Option, c: Class) { - match iv { - None => self.dead = true, - Some((lo, hi)) => { - let (w32, w64) = widths(c); - if !(fits(lo, w32) && fits(hi, w32)) { - self.a32 = false; - } - if !(fits(lo, w64) && fits(hi, w64)) { - self.a64 = false; - } - } - } - } -} - -fn hull(a: Iv, b: Iv) -> Iv { - (a.0.min(b.0), a.1.max(b.1)) -} -fn hull_opt(a: Option, b: Iv) -> Option { - Some(match a { - None => b, - Some(a) => hull(a, b), - }) -} -fn mul(a: i128, b: i128) -> Option { - a.checked_mul(b) -} -fn add(a: i128, b: i128) -> Option { - a.checked_add(b) -} -fn term(w: i128, l: i128, h: i128) -> Option { - let (x, y) = (mul(w, l)?, mul(w, h)?); - Some((x.min(y), x.max(y))) -} -fn corner(a: Iv, b: Iv) -> Option { - let c = [mul(a.0, b.0)?, mul(a.0, b.1)?, mul(a.1, b.0)?, mul(a.1, b.1)?]; - Some((*c.iter().min()?, *c.iter().max()?)) -} -/// `A(K, b)` (§8.2). -fn psum(terms: &[Iv], b: i128) -> Option { - let mut lo = b.min(0); - let mut hi = b.max(0); - for t in terms { - lo = add(lo, t.0.min(0))?; - hi = add(hi, t.1.max(0))?; - } - Some((lo, hi)) -} -fn floor_sh(v: i128, s: u32) -> i128 { - if s >= 127 { if v < 0 { -1 } else { 0 } } else { v >> s } -} - -/// The `rq` rules for one channel: `rq.p`, `rq.q`, `rq.y` from `rq.t`. -fn rq_rules(t: Iv, m: Option, s: u32, r: Round, post: i64) -> Option<(Iv, Iv, Iv)> { - let m = m.unwrap_or(1) as i128; - let p = term(m, t.0, t.1)?; - let a = if r != Round::Floor && s >= 1 { 1i128.checked_shl(s - 1).filter(|_| s - 1 < 127)? } else { 0 }; - let rp = (p.0, add(p.1, a)?); - let q = (round(p.0, s, r)?, round(p.1, s, r)?); - let y = (add(q.0, post as i128)?, add(q.1, post as i128)?); - Some((rp, q, y)) -} - -/// The intermediates and the producer result of a whole `rq`, hulled over channels, -/// given each channel's `rq.t`. -fn rq_all(acc: &mut Acc, ts: &[Option], rq: &Rq) -> Option { - let (mut t, mut p, mut q, mut y) = (None, None, None, None); - for (o, ti) in ts.iter().enumerate() { - let ti = (*ti)?; - let (rp, rq_, ry) = rq_rules(ti, rq.mult(o), rq.shift(o), rq.round, rq.post(o))?; - t = hull_opt(t, ti); - p = hull_opt(p, rp); - q = hull_opt(q, rq_); - y = hull_opt(y, ry); - } - acc.class(t, Class::Acc); - acc.class(p, Class::Product); - acc.class(q, Class::Acc); - acc.class(y, Class::Acc); - y -} - -fn exp_rule(acc: &mut Acc, u: Iv) { - acc.class(Some(u), Class::Acc); - acc.class(Some((45426 * (u.0 / 45426), 45426 * (u.1 / 45426))), Class::Acc); - acc.class(Some((43245 * 43245, 88670 * 88670)), Class::Acc); - acc.class(Some((0, 23495 * ((88670i128 * 88670) >> 16))), Class::Acc); -} - -fn fits64(v: i128) -> bool { - fits(v, 64) -} - -/// The profiles `g` meets, given the sizes the load plan gave (`None` when the -/// inputs declare none). -pub fn verdict(g: &Graph, sizes: Option<&[(u64, u64)]>) -> Verdict { - let mut a = Acc { a32: true, a64: true, dead: false }; - // Inputs and scalars: their declared ranges. - for i in &g.inputs { - let t = &g.tensors[i.tensor as usize]; - a.class(Some((t.lo as i128, t.hi as i128)), Class::Tensor); - } - for s in &g.scalars { - a.class(Some((s.lo as i128, s.hi as i128)), Class::Tensor); - } - let mut iv: Vec> = vec![None; g.tensors.len()]; - for i in &g.inputs { - let t = &g.tensors[i.tensor as usize]; - iv[i.tensor as usize] = Some((t.lo as i128, t.hi as i128)); - } - for op in &g.ops { - let outs = node(&mut a, g, op, &iv, sizes); - for (k, &t) in op.outs.iter().enumerate() { - let rec = &g.tensors[t as usize]; - let r = outs.as_ref().and_then(|o| o.get(k).copied().flatten()); - a.class(r, Class::Tensor); - let after = r.map(|(lo, hi)| match rec.policy { - Policy::Derived => (lo, hi), - Policy::Clamp => (lo.clamp(rec.lo as i128, rec.hi as i128), hi.clamp(rec.lo as i128, rec.hi as i128)), - Policy::Check => (lo.max(rec.lo as i128), hi.min(rec.hi as i128)), - }); - if let Some((lo, hi)) = after - && lo > hi - { - a.dead = true; - } - if rec.policy == Policy::Check { - a.a32 = false; - } - iv[t as usize] = after; - } - params32(&mut a, op); - } - Verdict { acc32: a.a32 && a.a64 && !a.dead, acc64: a.a64 && !a.dead } -} - -/// The parameter conditions of §7.2. -fn params32(a: &mut Acc, op: &crate::graph::Op) { - let f32_ = |v: i64| fits(v as i128, 32); - let rq_ok = |rq: &Rq| rq.mult.iter().all(|&m| f32_(m)) && rq.shift.iter().all(|&s| s <= 63) && (rq.bias_kind != BiasKind::Post || rq.bias.iter().all(|&b| f32_(b))); - let ok = match &op.p { - Params::Conv { rq, w, .. } | Params::ConvT { rq, w, .. } => rq_ok(rq) && w.iter().all(|&x| f32_(x)), - Params::Rescale(rq) | Params::Mul(rq) | Params::Gram { rq, .. } | Params::Apply { rq, .. } => rq_ok(rq), - Params::Chscale { shift, m, .. } => *shift <= 63 && m.iter().all(|&x| f32_(x)), - Params::Igdn { gf, frac, gamma, .. } => *gf <= 63 && *frac <= 63 && gamma.iter().all(|&x| f32_(x)), - Params::Leaky { a: s, .. } => f32_(*s), - _ => true, - }; - if !ok { - a.a32 = false; - } -} - -/// One node: classes its intermediates into `a` and returns its producer results. -fn node(a: &mut Acc, g: &Graph, op: &crate::graph::Op, iv: &[Option], sizes: Option<&[(u64, u64)]>) -> Option>> { - let x = iv[op.ins[0] as usize]; - let Some((l, h)) = x else { - a.dead = true; - return None; - }; - let one = |r: Option| Some(vec![r]); - let cin = g.tensors[op.ins[0] as usize].channels as usize; - match (&op.p, op.code) { - (Params::Conv { cout, kh, kw, groups, rq, w, .. }, _) => { - let (cout, kk, cg) = (*cout as usize, (*kh * *kw) as usize, cin / *groups as usize); - let mut tm: Option = None; - let mut accs: Option = None; - let mut ts = Vec::with_capacity(cout); - for o in 0..cout { - let mut terms = Vec::with_capacity(cg * kk); - for k in 0..cg * kk { - let t = term(w[o * cg * kk + k] as i128, l, h); - match t { - Some(t) => { - terms.push(t); - tm = hull_opt(tm, t); - } - None => a.dead = true, - } - } - let ac = psum(&terms, rq.pre(o) as i128); - if let Some(ac) = ac { - accs = hull_opt(accs, ac); - } else { - a.dead = true; - } - ts.push(ac); - } - a.class(tm.or(Some((0, 0))), Class::Acc); - a.class(accs, Class::Acc); - one(rq_all(a, &ts, rq)) - } - (Params::ConvT { cout, kh, kw, sh, sw, rq, w, .. }, _) => { - let (cout, kh, kw, sh, sw) = (*cout as usize, *kh as usize, *kw as usize, *sh as usize, *sw as usize); - let mut tm: Option = None; - let mut accs: Option = None; - let mut ts = Vec::with_capacity(cout); - for o in 0..cout { - let mut all: Option = None; - for ry in 0..sh { - for rx in 0..sw { - let mut terms = Vec::new(); - for ci in 0..cin { - for i in (ry..kh).step_by(sh) { - for j in (rx..kw).step_by(sw) { - match term(w[((ci * cout + o) * kh + i) * kw + j] as i128, l, h) { - Some(t) => { - terms.push(t); - tm = hull_opt(tm, t); - } - None => a.dead = true, - } - } - } - } - match psum(&terms, rq.pre(o) as i128) { - Some(p) => all = hull_opt(all, p), - None => a.dead = true, - } - } - } - accs = match (accs, all) { - (Some(x), Some(y)) => Some(hull(x, y)), - (None, y) => y, - (x, None) => x, - }; - ts.push(all); - } - a.class(tm.or(Some((0, 0))), Class::Acc); - a.class(accs, Class::Acc); - one(rq_all(a, &ts, rq)) - } - (Params::Rescale(rq), _) => { - let ts: Vec> = (0..cin).map(|c| Some((add(l, rq.pre(c) as i128)?, add(h, rq.pre(c) as i128)?))).collect(); - one(rq_all(a, &ts, rq)) - } - (Params::Chscale { scalar, round: r, shift, m, .. }, _) => { - let s = g.scalars[*scalar as usize]; - let (mut p, mut q) = (None, None); - for c in 0..cin { - for row in s.lo..=s.hi { - let (rp, rq_, _) = rq_rules((l, h), Some(m[row as usize * cin + c]), *shift as u32, *r, 0)?; - p = hull_opt(p, rp); - q = hull_opt(q, rq_); - } - } - a.class(Some((l, h)), Class::Acc); - a.class(p, Class::Product); - a.class(q, Class::Acc); - a.class(q, Class::Acc); - one(q) - } - (Params::Mul(rq), _) => { - let b = iv[op.ins[1] as usize]?; - let mp = corner((l, h), b); - a.class(mp, Class::Acc); - let ts = vec![mp; cin]; - one(rq_all(a, &ts, rq)) - } - (Params::Gram { rq, .. }, _) | (Params::Apply { rq, .. }, _) => { - let b = iv[op.ins[1] as usize]?; - let t = corner((l, h), b); - a.class(t, Class::Acc); - let n = match op.code { - GRAM => { - let s = sizes?; - let (h0, w0) = s[op.ins[0] as usize]; - let (h1, w1) = s[op.ins[1] as usize]; - (h0 * w0).max(h1 * w1) as i128 - } - _ => (cin / match op.p { Params::Apply { groups, .. } => groups as usize, _ => 1 }) as i128, - }; - let acc = t.and_then(|t| Some((mul(n, t.0.min(0))?, mul(n, t.1.max(0))?))); - a.class(acc, Class::Acc); - let ts = vec![acc; cin]; - one(rq_all(a, &ts, rq)) - } - (_, ADD) => { - let b = iv[op.ins[1] as usize]?; - one(Some((add(l, b.0)?, add(h, b.1)?))) - } - (_, CHUNK_ADD) => one(Some((mul(2, l)?, mul(2, h)?))), - (Params::Clamp { lo, hi }, _) => one(Some((l.clamp(*lo as i128, *hi as i128), h.clamp(*lo as i128, *hi as i128)))), - (_, RELU) => one(Some((l.max(0), h.max(0)))), - (_, ABS) => one(Some(if l >= 0 { (l, h) } else if h <= 0 { (-h, -l) } else { (0, (-l).max(h)) })), - (Params::Leaky { a: s, f }, _) => { - let mut r: Option = None; - if l < 0 { - let p = corner((l, h.min(-1)), (*s as i128, *s as i128)); - a.class(p, Class::Acc); - let p = p?; - r = Some((floor_sh(p.0, *f), floor_sh(p.1, *f))); - } else { - a.class(Some((0, 0)), Class::Acc); - } - if h >= 0 { - r = hull_opt(r, (l.max(0), h)); - } - one(r) - } - (Params::Lut16 { t, .. }, _) => { - if l < -32767 || h > 32767 { - a.dead = true; - return None; - } - let vals = (l..=h).map(|u| t[(u + 32768) as usize] as i128); - let (mn, mx) = vals.fold((i128::MAX, i128::MIN), |(a, b), v| (a.min(v), b.max(v))); - one(Some((mn, mx))) - } - (Params::Igdn { gf, frac, gamma, beta, .. }, _) => { - let x2 = if l <= 0 && h >= 0 { (0, mul(l, l)?.max(mul(h, h)?)) } else { (mul(l, l)?.min(mul(h, h)?), mul(l, l)?.max(mul(h, h)?)) }; - a.class(Some(x2), Class::Wide); - let (mut gx, mut tm, mut nn, mut rr) = (None, None, None, None); - for i in 0..cin { - let mut terms = Vec::with_capacity(cin); - let (mut flo, mut fhi) = (beta[i] as i128, beta[i] as i128); - for j in 0..cin { - let g2 = corner((gamma[i * cin + j] as i128, gamma[i * cin + j] as i128), x2)?; - gx = hull_opt(gx, g2); - let t = (floor_sh(g2.0, *gf), floor_sh(g2.1, *gf)); - tm = hull_opt(tm, t); - terms.push(t); - flo = add(flo, t.0)?; - fhi = add(fhi, t.1)?; - } - nn = hull_opt(nn, psum(&terms, beta[i] as i128)?); - let r = ((flo.max(0) as u128).isqrt() as i128, (fhi.max(0) as u128).isqrt() as i128); - rr = hull_opt(rr, r); - } - a.class(gx, Class::Product); - a.class(tm, Class::Wide); - a.class(nn, Class::Wide); - a.class(rr, Class::Acc); - let xr = corner((l, h), rr?); - a.class(xr, Class::Wide); - let xr = xr?; - one(Some((floor_sh(xr.0, *frac), floor_sh(xr.1, *frac)))) - } - (Params::LayerNorm { eps, gamma, beta, .. }, _) => { - let c = cin as i128; - let e = *eps as i128; - let r0 = (e as u128).isqrt() as i128; - let k = (1i128 << 32) / r0; - let d = h - l; - a.class(Some((mul(c, l.min(0))?, mul(c, h.max(0))?)), Class::Wide); - a.class(Some((mul(c, l)? - c / 2, add(mul(c, h)?, c / 2)?)), Class::Wide); - a.class(Some((-d, d)), Class::Acc); - a.class(mul(d, d).and_then(|dd| Some((0, mul(c, dd)?))), Class::Wide); - a.class(mul(d, d).and_then(|dd| Some((e, add(dd, e)?))), Class::Wide); - a.class(Some((1 << 32, 1 << 32)), Class::Acc); - a.class(Some((0, k)), Class::Acc); - let ic = (c as u128).isqrt() as i128; - let icc = if ic * ic == c { ic } else { ic + 1 }; - let dmax_l = mul(d, k); - let dmax_r = mul(icc, 1i128 << 32).and_then(|v| mul(v, r0 + 1)).map(|v| (v + r0 - 1) / r0); - let dd = match (dmax_l, dmax_r) { - (Some(x), Some(y)) => Some(x.min(y)), - (x, y) => x.or(y), - }; - a.class(dd.map(|v| (-v, v)), Class::Wide); - let nmax = mul(icc, 1i128 << 16).and_then(|v| mul(v, r0 + 1)).map(|v| v / r0 + 1); - let n1 = mul(d, k).map(|v| (v >> 16) + 1); - let n = match (n1, nmax) { - (Some(x), Some(y)) => x.min(y), - (x, y) => x.or(y)?, - }; - a.class(Some((-n, n)), Class::Acc); - let (mut ng, mut pr) = (None, None); - for cc in 0..cin { - let gv = gamma[cc] as i128; - let t = corner((-n, n), (gv, gv))?; - ng = hull_opt(ng, t); - pr = hull_opt(pr, (add(t.0 >> 16, beta[cc] as i128)?, add(t.1 >> 16, beta[cc] as i128)?)); - } - a.class(ng, Class::Wide); - one(pr) - } - (Params::L2norm { eps }, _) => { - let s = sizes?; - let (hh, ww) = s[op.ins[0] as usize]; - let xm = l.abs().max(h.abs()); - let e = *eps as i128; - a.class(mul(xm, xm).and_then(|x2| mul((hh * ww) as i128, x2)).and_then(|v| add(v, e)).map(|v| (0, v)), Class::Wide); - a.class(Some((1 << 32, 1 << 32)), Class::Acc); - a.class(Some((0, (1i128 << 32) / (e as u128).isqrt() as i128)), Class::Acc); - a.class(Some((-(1 << 32), 1 << 32)), Class::Wide); - one(Some((-(1 << 16), 1 << 16))) - } - (_, SOFTMAX) => { - let s = sizes?; - let wm = s[op.ins[0] as usize].1 as i128; - a.class(Some((l - h, 0)), Class::Acc); - exp_rule(a, (0, h - l)); - a.class(Some((0, wm * 65553)), Class::Acc); - a.class(Some((0, 65553 * 65536 + (wm * 65553) / 2)), Class::Acc); - one(Some((0, 1 << 16))) - } - (_, SIGMOID) => { - let u = if l >= 0 { (l, h) } else if h <= 0 { (-h, -l) } else { (0, (-l).max(h)) }; - exp_rule(a, u); - a.class(Some((0, 65553 * 65536)), Class::Acc); - one(Some((0, 1 << 16))) - } - (Params::Elu { alpha }, _) => { - exp_rule(a, ((-h).max(0), (-l).max(0))); - let p = corner((*alpha as i128, *alpha as i128), (-(1 << 16), 17)); - a.class(p, Class::Wide); - let mut r: Option = None; - if h > 0 { - r = Some((l.max(1), h)); - } - if l <= 0 { - let p = p?; - r = hull_opt(r, (p.0 >> 16, p.1 >> 16)); - } - one(r) - } - (_, CONCAT) | (_, SUBPOS_MERGE) => { - let mut r = None; - for &t in &op.ins { - r = hull_opt(r, iv[t as usize]?); - } - one(r) - } - (Params::Fill { kind, value }, _) => { - if *kind == 0 { - one(Some((*value as i128, *value as i128))) - } else { - let s = g.scalars[*value as usize]; - one(Some((s.lo as i128, s.hi as i128))) - } - } - (_, SUBPOS_SPLIT) => Some(vec![Some((l, h)); 4]), - (Params::Crop { .. }, _) => one(Some((l, h))), - _ => one(Some((l, h))), - } -} - -/// Whether an `Operand` is a scalar; used by the generator to know whether a crop -/// needs a scalar. -pub fn is_scalar(o: Operand) -> bool { - matches!(o, Operand::Scalar(_)) -} - -/// Whether `v` fits `i64`. -pub fn fits_i64(v: i128) -> bool { - fits64(v) -} diff --git a/wai/wai-ops/src/graph.rs b/wai/wai-ops/src/graph.rs index aa66e5b42..c3d20db63 100644 --- a/wai/wai-ops/src/graph.rs +++ b/wai/wai-ops/src/graph.rs @@ -4,6 +4,7 @@ use alloc::vec; use alloc::vec::Vec; +use crate::bounds::Profile; use crate::code::{Code, Refusal, at_load}; pub const MAGIC: &[u8; 4] = b"WHG1"; @@ -308,7 +309,13 @@ impl<'a> R<'a> { .collect()) } fn zero(&mut self, n: usize, st: u8) -> Res<()> { - if self.take(n, st)?.iter().all(|&b| b == 0) { Ok(()) } else { Err(at_load(Code::ModelMismatch, st)) } + let s = self.take(n, st)?; + for k in 0..n { + if s[k] != 0 { + return Err(at_load(Code::ModelMismatch, st)); + } + } + Ok(()) } } @@ -979,19 +986,18 @@ pub fn smallest_width(v: &[i64], allowed: &[u8]) -> u8 { 8 } -/// A graph that passed every load step of §10.5. Only [`load`] makes one, and -/// [`crate::interp::run`] takes nothing else, so no graph decodes without passing -/// load step 8: a [`Graph`] that was parsed, lowered or built in place runs only -/// after `load` of its bytes. +/// A graph that passed every load step of §10.5, step 8 included, under a profile. +/// Only [`load`] makes one, and [`crate::interp::run`] takes nothing else, so no graph +/// decodes without passing load step 8: a [`Graph`] that was parsed, lowered or built +/// in place runs only after `load` of its bytes. /// /// ``` -/// # #[cfg(feature = "uncertified")] { -/// use wai_ops::{Sequence, Tensor, graph, lower, run}; +/// use wai_ops::{Profile, Sequence, Tensor, graph, lower, run}; /// let set = lower::int_synth(br#"{"layers":[{"in_ch":1,"out_ch":3,"k":1,"stride":1,"pad":0,"weight":[1,2,3],"bias":[0,0,0]}]}"#).unwrap(); -/// let g = graph::load(&set.get("synth").unwrap().to_bytes()).unwrap(); +/// let g = graph::load(&set.get("synth").unwrap().to_bytes(), Profile::Acc64).unwrap(); +/// assert!(g.meets(Profile::Acc32)); /// let out = run(&g, &[Tensor::new(1, 1, 1, vec![5])], &[], &mut Sequence::new()).unwrap(); /// assert_eq!(out[0].data, vec![5, 10, 15]); -/// # } /// ``` /// /// A lowered graph that has not been loaded does not compile as an argument to `run`: @@ -1005,6 +1011,7 @@ pub fn smallest_width(v: &[i64], allowed: &[u8]) -> u8 { #[derive(Clone, Debug, PartialEq, Eq)] pub struct Loaded { g: Graph, + acc32: bool, } impl Loaded { @@ -1012,6 +1019,15 @@ impl Loaded { pub fn graph(&self) -> &Graph { &self.g } + + /// Whether the graph's verdict meets `p` (§8.5). A loaded graph meets the profile + /// it was loaded under, and every graph that meets `acc32` also meets `acc64`. + pub fn meets(&self, p: Profile) -> bool { + match p { + Profile::Acc64 => true, + Profile::Acc32 => self.acc32, + } + } } impl core::ops::Deref for Loaded { @@ -1021,28 +1037,20 @@ impl core::ops::Deref for Loaded { } } -/// Load a graph: steps 1–7 of §10.5, then step 8. +/// Load a graph under the profile `p` of the operator implementation that is to run +/// it: steps 1–7 of §10.5, then step 8, the bounds pass (§8), `lut16`'s range check +/// (§5.6) and `p` against the graph's verdict (§8.6). Every refusal is +/// `model_mismatch`, or `too_large` for a size. /// -/// Step 8 (the bounds pass, `lut16`'s range check, and the capability's profile -/// against the verdict) is not built yet. Without the `uncertified` feature it -/// refuses every graph (`model_mismatch` at step 8), so no [`Loaded`] exists and -/// nothing decodes; with the feature, which only the tests, the conformance tool and -/// its browser-engine build enable, it is skipped. -pub fn load(b: &[u8]) -> Res { +/// A set of several graphs meets `p` exactly when each of its graphs does, so a +/// driver that loads every graph of a set under its capability's declared profile +/// refuses exactly the sets whose certificate does not meet it. +pub fn load(b: &[u8], p: Profile) -> Res { let g = Graph::parse(b)?; - crate::plan::load_plan(&g)?; - step8(&g)?; - Ok(Loaded { g }) -} - -#[cfg(feature = "uncertified")] -fn step8(_g: &Graph) -> Res<()> { - Ok(()) -} - -#[cfg(not(feature = "uncertified"))] -fn step8(_g: &Graph) -> Res<()> { - Err(Refusal::new(Code::ModelMismatch, crate::code::Site::Load(8))) + let sizes = crate::plan::load_plan(&g)?; + let bd = crate::bounds::step8(&g, sizes.as_deref(), p)?; + let acc32 = bd.meets(&g, Profile::Acc32); + Ok(Loaded { g, acc32 }) } #[cfg(test)] @@ -1067,18 +1075,22 @@ mod tests { assert_eq!(Graph::parse(&b).unwrap().to_bytes(), b); } - /// Without the `uncertified` switch, load step 8 refuses every graph: nothing - /// decodes through an uncertified graph outside the tests and the tool. - #[cfg(not(feature = "uncertified"))] + /// Load step 8: the graph loads under both profiles; with an input range past + /// i32 it loads under `acc64` only; with a `check` range that its producer cannot + /// meet, under neither. #[test] - fn step_8_refuses_every_graph_until_the_certifier_exists() { - let r = load(&tiny().to_bytes()).unwrap_err(); - assert_eq!(r, Refusal::new(Code::ModelMismatch, crate::code::Site::Load(8))); - } - - #[cfg(feature = "uncertified")] - #[test] - fn the_switch_skips_step_8() { - assert!(load(&tiny().to_bytes()).is_ok()); + fn step_8_applies_the_profile() { + let g = tiny(); + let l = load(&g.to_bytes(), Profile::Acc32).unwrap(); + assert!(l.meets(Profile::Acc32) && l.meets(Profile::Acc64)); + let mut wide = tiny(); + wide.tensors[0] = TensorRec::check(1, -5, 1 << 40); + assert_eq!(load(&wide.to_bytes(), Profile::Acc32).unwrap_err(), Refusal::new(Code::ModelMismatch, crate::code::Site::Load(8))); + assert!(!load(&wide.to_bytes(), Profile::Acc64).unwrap().meets(Profile::Acc32)); + let mut empty = tiny(); + empty.tensors[1] = TensorRec::check(1, -9, -1); + for p in Profile::ALL { + assert_eq!(load(&empty.to_bytes(), p).unwrap_err(), Refusal::new(Code::ModelMismatch, crate::code::Site::Load(8))); + } } } diff --git a/wai/wai-ops/src/interp.rs b/wai/wai-ops/src/interp.rs index 446bf89c5..5383341eb 100644 --- a/wai/wai-ops/src/interp.rs +++ b/wai/wai-ops/src/interp.rs @@ -1,11 +1,11 @@ //! The reference interpreter of the graph operators (§5). //! //! Tensors hold `i64`. Every intermediate is formed in `i128`, which holds every -//! value a graph certified for `acc64` forms (§7.1), and every step is checked: a -//! graph whose arithmetic would leave `i128`, or whose producer result would leave -//! `i64`, is one that load step 8 refuses once the certifier exists, and here, where -//! step 8 is not built yet, the decode is refused (`model_mismatch`) at that operator -//! instead of wrapping. No certified graph reaches that refusal. +//! value a graph certified for `acc64` forms (§7.1), and every step is still checked: +//! a graph whose arithmetic would leave `i128`, or whose producer result would leave +//! `i64`, is one that load step 8 refuses, so [`run`], which takes only a loaded graph, +//! never meets one. Were it to, the decode would be refused (`model_mismatch`) at that +//! operator instead of wrapping. use alloc::vec; use alloc::vec::Vec; @@ -50,8 +50,27 @@ impl Sequence { type Res = Result; -/// The refusal an uncertified graph meets where its arithmetic leaves the widths a -/// certified one keeps to. See the module documentation. +/// An observer of a run: [`run_observed`] reports to it every value an operator forms +/// under one of §5's named intermediates (the keys of §8.5, Table 8.5-A), and every +/// element of each producer result before its tensor's policy (`out.`), with the +/// operator's index. A certificate's intervals are claims about exactly these values, +/// so an observer can hold a decode to its certificate. +pub trait Observe { + fn see(&mut self, op: u32, key: &'static str, v: i128); +} + +/// The observer of an ordinary run: it sees nothing, and compiles to nothing. +pub struct Quiet; + +impl Observe for Quiet { + #[inline(always)] + fn see(&mut self, _op: u32, _key: &'static str, _v: i128) {} +} + +const OUT: [&str; 4] = ["out.0", "out.1", "out.2", "out.3"]; + +/// The refusal a graph would meet where its arithmetic left the widths a certified +/// one keeps to; load step 8 makes it unreachable. See the module documentation. fn wide(at: u32) -> Refusal { Refusal::new(Code::ModelMismatch, Site::Op(at)) } @@ -73,27 +92,51 @@ pub fn round(p: i128, s: u32, r: Round) -> Option { } } +/// The values `rq.p` stands for (§5.1): `p`, and `p + 2^(s−1)` where `round` adds it. +fn see_p(obs: &mut O, at: u32, p: i128, s: u32, r: Round) { + obs.see(at, "rq.p", p); + if r != Round::Floor && s >= 1 { + if let Some(a) = p.checked_add(1i128 << (s - 1)) { + obs.see(at, "rq.p", a); + } + } +} + /// `rq_o(v)` (§5.1). -fn rq_apply(rq: &Rq, o: usize, v: i128) -> Option { +pub(crate) fn rq_apply(rq: &Rq, o: usize, v: i128, at: u32, obs: &mut O) -> Option { let t = v.checked_add(rq.pre(o) as i128)?; + obs.see(at, "rq.t", t); let p = match rq.mult(o) { Some(m) => t.checked_mul(m as i128)?, None => t, }; + see_p(obs, at, p, rq.shift(o), rq.round); let q = round(p, rq.shift(o), rq.round)?; - q.checked_add(rq.post(o) as i128) + obs.see(at, "rq.q", q); + let y = q.checked_add(rq.post(o) as i128)?; + obs.see(at, "rq.y", y); + Some(y) } /// `exp_neg_q16(x)` (§2), for `x ≤ 0`. pub fn exp_neg_q16(x: i128) -> i128 { + exp_observed(x, 0, &mut Quiet) +} + +/// `exp_neg_q16(x)`, reporting `exp.negx`, `exp.nl`, `exp.t2` and `exp.c`. +pub(crate) fn exp_observed(x: i128, at: u32, obs: &mut O) -> i128 { let u = -x; + obs.see(at, "exp.negx", u); let n = u / 45426; let g = 45426 * n; + obs.see(at, "exp.nl", g); let r = x + g; let t = r + 88670; let t2 = t * t; + obs.see(at, "exp.t2", t2); let q = t2 >> 16; let c = 23495 * q; + obs.see(at, "exp.c", c); let y = (c >> 16) + 22544; if n >= 63 { 0 } else { y >> n } } @@ -113,6 +156,12 @@ fn to64(v: i128, at: u32) -> Res { /// from `seq` (§10.3). `scalars` holds every scalar's value. Returns the graph's /// outputs, in output-table order. A refused decode leaves `seq` as it was. pub fn run(g: &Loaded, inputs: &[Tensor], scalars: &[i64], seq: &mut Sequence) -> Res> { + run_observed(g, inputs, scalars, seq, &mut Quiet) +} + +/// [`run`], reporting every named intermediate and producer result to `obs` +/// ([`Observe`]). The outputs and refusals are [`run`]'s. +pub fn run_observed(g: &Loaded, inputs: &[Tensor], scalars: &[i64], seq: &mut Sequence, obs: &mut O) -> Res> { let g: &Graph = g.graph(); // The inputs, data and state, in input-table order. let n_data = g.inputs.iter().filter(|i| i.kind == 0).count(); @@ -155,7 +204,12 @@ pub fn run(g: &Loaded, inputs: &[Tensor], scalars: &[i64], seq: &mut Sequence) - vals[rec.tensor as usize] = Some(t); } for (i, op) in g.ops.iter().enumerate() { - let outs = eval(g, op, i as u32, &vals, &hw, scalars)?; + let outs = eval(g, op, i as u32, &vals, &hw, scalars, obs)?; + for (k, ten) in outs.iter().enumerate() { + for &v in &ten.data { + obs.see(i as u32, OUT[k], v as i128); + } + } for (&t, mut ten) in op.outs.iter().zip(outs) { let tr = &g.tensors[t as usize]; if !apply_policy(tr.policy, tr.lo, tr.hi, &mut ten.data) { @@ -189,7 +243,7 @@ fn get<'a>(vals: &'a [Option], t: u32) -> &'a Tensor { } /// Map every element of `x` through `f`. -fn map(x: &Tensor, at: u32, f: impl Fn(i128) -> Option) -> Res { +fn map(x: &Tensor, at: u32, mut f: impl FnMut(i128) -> Option) -> Res { let mut d = Vec::with_capacity(x.data.len()); for &v in &x.data { d.push(to64(f(v as i128).ok_or(wide(at))?, at)?); @@ -198,7 +252,7 @@ fn map(x: &Tensor, at: u32, f: impl Fn(i128) -> Option) -> Res { } /// Map every element of channel `c` of `x` through `f(c, v)`. -fn map_c(x: &Tensor, at: u32, f: impl Fn(usize, i128) -> Option) -> Res { +fn map_c(x: &Tensor, at: u32, mut f: impl FnMut(usize, i128) -> Option) -> Res { let plane = x.h as usize * x.w as usize; let mut d = Vec::with_capacity(x.data.len()); for (k, &v) in x.data.iter().enumerate() { @@ -207,368 +261,533 @@ fn map_c(x: &Tensor, at: u32, f: impl Fn(usize, i128) -> Option) -> Res], hw: &[(u64, u64)], sc: &[i64]) -> Res> { +#[allow(clippy::too_many_arguments)] +pub(crate) fn eval(g: &Graph, op: &crate::graph::Op, at: u32, vals: &[Option], hw: &[(u64, u64)], sc: &[i64], obs: &mut O) -> Res> { let x = get(vals, op.ins[0]); - let (c, h, w) = (x.c as usize, x.h as usize, x.w as usize); let out_c = |k: usize| g.tensors[op.outs[k] as usize].channels; let (oh, ow) = hw[op.outs[0] as usize]; let (oh, ow) = (oh as usize, ow as usize); - let one = |t: Tensor| Ok(vec![t]); + let one = |t: Res| Ok(vec![t?]); + let u = |v: u32| v as usize; match (&op.p, op.code) { - (Params::Conv { cout, kh, kw, sh, sw, ph, pw, groups, rq, w: wt, .. }, _) => { - let (cout, kh, kw, sh, sw, ph, pw, groups) = - (*cout as usize, *kh as usize, *kw as usize, *sh as usize, *sw as usize, *ph as usize, *pw as usize, *groups as usize); - let (cg, og) = (c / groups, cout / groups); - let mut d = vec![0i64; cout * oh * ow]; - for o in 0..cout { - let base = (o / og) * cg; - for y in 0..oh { - for xx in 0..ow { - let mut acc: i128 = 0; - for ci in 0..cg { - for i in 0..kh { - let iy = y * sh + i; - if iy < ph || iy - ph >= h { - continue; - } - for j in 0..kw { - let ix = xx * sw + j; - if ix < pw || ix - pw >= w { - continue; - } - let wv = wt[((o * cg + ci) * kh + i) * kw + j] as i128; - let term = wv * x.at(base + ci, iy - ph, ix - pw) as i128; - acc = acc.checked_add(term).ok_or(wide(at))?; - } - } - } - d[(o * oh + y) * ow + xx] = to64(rq_apply(rq, o, acc).ok_or(wide(at))?, at)?; - } - } - } - one(Tensor::new(cout as u32, oh as u32, ow as u32, d)) + (Params::Conv { cout, kh, kw, sh, sw, ph, pw, groups, rq, w, .. }, _) => { + one(k_conv(x, u(*cout), u(*kh), u(*kw), u(*sh), u(*sw), u(*ph), u(*pw), u(*groups), rq, w, oh, ow, at, obs)) } - (Params::ConvT { cout, kh, kw, sh, sw, ph, pw, oph, opw, rq, w: wt, .. }, _) => { - let (cout, kh, kw, sh, sw, ph, pw) = - (*cout as usize, *kh as usize, *kw as usize, *sh as usize, *sw as usize, *ph as usize, *pw as usize); - let uh = (h - 1) * sh + kh + *oph as usize; - let uw = (w - 1) * sw + kw + *opw as usize; - // The scatter form: the same products as §5.3's gather, summed exactly. - let mut plane = vec![0i128; cout * uh * uw]; - for ci in 0..c { - for u in 0..h { - for v in 0..w { - let xv = x.at(ci, u, v) as i128; - if xv == 0 { - continue; - } - for o in 0..cout { - for i in 0..kh { - let row = (o * uh + u * sh + i) * uw + v * sw; - for j in 0..kw { - let wv = wt[((ci * cout + o) * kh + i) * kw + j] as i128; - let cell = &mut plane[row + j]; - *cell = cell.checked_add(wv * xv).ok_or(wide(at))?; - } - } - } - } - } - } - let mut d = vec![0i64; cout * oh * ow]; - for o in 0..cout { - for y in 0..oh { - for xx in 0..ow { - let acc = plane[(o * uh + y + ph) * uw + xx + pw]; - d[(o * oh + y) * ow + xx] = to64(rq_apply(rq, o, acc).ok_or(wide(at))?, at)?; - } - } - } - one(Tensor::new(cout as u32, oh as u32, ow as u32, d)) - } - (Params::Rescale(rq), _) => one(map_c(x, at, |o, v| rq_apply(rq, o, v))?), - (Params::Chscale { scalar, round: r, shift, m, .. }, _) => { - let row = sc[*scalar as usize] as usize; - one(map_c(x, at, |o, v| round(v.checked_mul(m[row * c + o] as i128)?, *shift as u32, *r))?) - } - (Params::Mul(rq), _) => { - let b = get(vals, op.ins[1]); - let plane = h * w; - let mut d = Vec::with_capacity(x.data.len()); - for o in 0..c { - let bo = if b.c as usize == c { o } else { 0 }; - for k in 0..plane { - let p = (x.data[o * plane + k] as i128) * (b.data[bo * plane + k] as i128); - d.push(to64(rq_apply(rq, o, p).ok_or(wide(at))?, at)?); - } - } - one(Tensor::new(x.c, x.h, x.w, d)) - } - (Params::Lut16 { t, .. }, _) => one(map(x, at, |v| { - let i = v + 32768; - if (0..65536).contains(&i) { Some(t[i as usize] as i128) } else { None } - })?), - (_, ADD) => { - let b = get(vals, op.ins[1]); - let mut d = Vec::with_capacity(x.data.len()); - for (&p, &q) in x.data.iter().zip(&b.data) { - d.push(to64(p as i128 + q as i128, at)?); - } - one(Tensor::new(x.c, x.h, x.w, d)) + (Params::ConvT { cout, kh, kw, sh, sw, ph, pw, oph, opw, rq, w, .. }, _) => { + one(k_conv_t(x, u(*cout), u(*kh), u(*kw), u(*sh), u(*sw), u(*ph), u(*pw), u(*oph), u(*opw), rq, w, oh, ow, at, obs)) } + (Params::Rescale(rq), _) => one(k_rescale(x, rq, at, obs)), + (Params::Chscale { scalar, round: r, shift, m, .. }, _) => one(k_chscale(x, sc[*scalar as usize] as usize, *r, *shift as u32, m, at, obs)), + (Params::Mul(rq), _) => one(k_mul(x, get(vals, op.ins[1]), rq, at, obs)), + (Params::Lut16 { t, .. }, _) => one(k_lut16(x, t, at)), + (_, ADD) => one(k_add(x, get(vals, op.ins[1]), at)), (_, CONCAT) => { - let mut d = Vec::new(); - for &t in &op.ins { - d.extend_from_slice(&get(vals, t).data); - } - one(Tensor::new(out_c(0), x.h, x.w, d)) + let ins: Vec<&Tensor> = op.ins.iter().map(|&t| get(vals, t)).collect(); + Ok(vec![k_concat(&ins, out_c(0))]) } - (_, CHUNK_ADD) => { - let half = (c / 2) * h * w; - let mut d = Vec::with_capacity(half); - for k in 0..half { - d.push(to64(x.data[k] as i128 + x.data[k + half] as i128, at)?); - } - one(Tensor::new((c / 2) as u32, x.h, x.w, d)) - } - (Params::Split { start, count }, _) => { - let plane = h * w; - let s = *start as usize * plane; - one(Tensor::new(*count, x.h, x.w, x.data[s..s + *count as usize * plane].to_vec())) - } - (Params::Shuffle { r }, PIXEL_SHUFFLE) => { - let r = *r as usize; - let co = c / (r * r); - let mut d = vec![0i64; c * h * w]; - for cc in 0..co { - for y in 0..h { - for xx in 0..w { - for i in 0..r { - for j in 0..r { - d[(cc * oh + y * r + i) * ow + xx * r + j] = x.at(cc * r * r + i * r + j, y, xx); - } - } - } - } - } - one(Tensor::new(co as u32, oh as u32, ow as u32, d)) - } - (Params::Shuffle { r }, _) => { - let r = *r as usize; - let mut d = vec![0i64; c * h * w]; - for cc in 0..c { - for y in 0..oh { - for xx in 0..ow { - for i in 0..r { - for j in 0..r { - d[((cc * r * r + i * r + j) * oh + y) * ow + xx] = x.at(cc, y * r + i, xx * r + j); - } - } - } - } - } - one(Tensor::new((c * r * r) as u32, oh as u32, ow as u32, d)) - } - (Params::Clamp { lo, hi }, _) => one(map(x, at, |v| Some(v.clamp(*lo as i128, *hi as i128)))?), - (_, RELU) => one(map(x, at, |v| Some(v.max(0)))?), - (Params::Leaky { a, f }, _) => one(map(x, at, |v| Some(if v >= 0 { v } else { (v * *a as i128) >> *f } ))?), - (_, ABS) => one(map(x, at, |v| Some(v.abs()))?), - (Params::PadRep { .. }, _) => { - let mut d = Vec::with_capacity(c * oh * ow); - for cc in 0..c { - for y in 0..oh { - for xx in 0..ow { - d.push(x.at(cc, y.min(h - 1), xx.min(w - 1))); - } - } - } - one(Tensor::new(x.c, oh as u32, ow as u32, d)) - } - (_, CROP_TO) => one(crop(x, 0, 0, oh, ow)), + (_, CHUNK_ADD) => one(k_chunk_add(x, at)), + (Params::Split { start, count }, _) => Ok(vec![k_split(x, u(*start), *count)]), + (Params::Shuffle { r }, PIXEL_SHUFFLE) => Ok(vec![k_pixel_shuffle(x, u(*r), oh, ow)]), + (Params::Shuffle { r }, _) => Ok(vec![k_pixel_unshuffle(x, u(*r), oh, ow)]), + (Params::Clamp { lo, hi }, _) => one(map(x, at, |v| Some(v.clamp(*lo as i128, *hi as i128)))), + (_, RELU) => one(map(x, at, |v| Some(v.max(0)))), + (Params::Leaky { a, f }, _) => one(k_leaky(x, *a, *f, at, obs)), + (_, ABS) => one(map(x, at, |v| Some(v.abs()))), + (Params::PadRep { .. }, _) => Ok(vec![k_pad_rep(x, oh, ow)]), + (_, CROP_TO) => Ok(vec![crop(x, 0, 0, oh, ow)]), (Params::Crop { y0, x0, .. }, _) => { let v = |o: &Operand| match *o { Operand::Const(k) => k as usize, Operand::Scalar(s) => sc[s as usize] as usize, }; - one(crop(x, v(y0), v(x0), oh, ow)) - } - (Params::Subpos { order }, SUBPOS_SPLIT) => { - let mut outs = Vec::with_capacity(4); - for &o in order { - let (a, b) = ((o >> 1) as usize, (o & 1) as usize); - let mut d = Vec::with_capacity(c * oh * ow); - for cc in 0..c { - for y in 0..oh { - for xx in 0..ow { - d.push(x.at(cc, 2 * y + a, 2 * xx + b)); - } - } - } - outs.push(Tensor::new(x.c, oh as u32, ow as u32, d)); - } - Ok(outs) + Ok(vec![crop(x, v(y0), v(x0), oh, ow)]) } + (Params::Subpos { order }, SUBPOS_SPLIT) => Ok(k_subpos_split(x, order, oh, ow)), (Params::Subpos { order }, _) => { - let mut d = vec![0i64; c * oh * ow]; - for (k, &o) in order.iter().enumerate() { - let (a, b) = ((o >> 1) as usize, (o & 1) as usize); - let t = get(vals, op.ins[k]); - for cc in 0..c { - for y in 0..h { - for xx in 0..w { - d[(cc * oh + 2 * y + a) * ow + 2 * xx + b] = t.at(cc, y, xx); - } - } - } - } - one(Tensor::new(x.c, oh as u32, ow as u32, d)) + let ins: Vec<&Tensor> = op.ins.iter().map(|&t| get(vals, t)).collect(); + Ok(vec![k_subpos_merge(&ins, order, oh, ow)]) } (Params::Fill { kind, value }, _) => { let v = if *kind == 0 { *value } else { sc[*value as usize] }; - one(Tensor::filled(out_c(0), x.h, x.w, v)) - } - (Params::Igdn { gf, frac, gamma, beta, .. }, _) => { - let mut d = vec![0i64; c * h * w]; - let plane = h * w; - let mut x2 = vec![0i128; c]; - for p in 0..plane { - for j in 0..c { - let v = x.data[j * plane + p] as i128; - x2[j] = v * v; - } - for i in 0..c { - let mut n = beta[i] as i128; - for j in 0..c { - let gx2 = (gamma[i * c + j] as i128).checked_mul(x2[j]).ok_or(wide(at))?; - n = n.checked_add(gx2 >> *gf).ok_or(wide(at))?; - } - let r = (n.max(0) as u128).isqrt() as i128; - let xr = (x.data[i * plane + p] as i128).checked_mul(r).ok_or(wide(at))?; - d[i * plane + p] = to64(xr >> *frac, at)?; - } - } - one(Tensor::new(x.c, x.h, x.w, d)) - } - (Params::LayerNorm { eps, gamma, beta, .. }, _) => { - let plane = h * w; - let mut d = vec![0i64; c * plane]; - let ci = c as i128; - for p in 0..plane { - let mut s: i128 = 0; - for k in 0..c { - s = s.checked_add(x.data[k * plane + p] as i128).ok_or(wide(at))?; - } - let m_num = s.checked_add((ci / 2) * s.signum()).ok_or(wide(at))?; - let m = m_num / ci; - let mut t: i128 = 0; - let mut dev = vec![0i128; c]; - for k in 0..c { - let dk = (x.data[k * plane + p] as i128) - m; - dev[k] = dk; - t = t.checked_add(dk.checked_mul(dk).ok_or(wide(at))?).ok_or(wide(at))?; - } - let v = t / ci; - let u = v.checked_add(*eps as i128).ok_or(wide(at))?; - let k = rsqrt_q16(u as u128); - for kk in 0..c { - let n = dev[kk].checked_mul(k).ok_or(wide(at))? >> 16; - let ng = n.checked_mul(gamma[kk] as i128).ok_or(wide(at))?; - d[kk * plane + p] = to64((ng >> 16).checked_add(beta[kk] as i128).ok_or(wide(at))?, at)?; - } - } - one(Tensor::new(x.c, x.h, x.w, d)) - } - (Params::L2norm { eps }, _) => { - let plane = h * w; - let mut d = vec![0i64; c * plane]; - for cc in 0..c { - let mut t: i128 = 0; - for p in 0..plane { - let v = x.data[cc * plane + p] as i128; - t = t.checked_add(v * v).ok_or(wide(at))?; - } - let u = t.checked_add(*eps as i128).ok_or(wide(at))?; - let k = rsqrt_q16(u as u128); - for p in 0..plane { - let vk = (x.data[cc * plane + p] as i128).checked_mul(k).ok_or(wide(at))?; - d[cc * plane + p] = to64(vk >> 16, at)?; - } - } - one(Tensor::new(x.c, x.h, x.w, d)) - } - (_, SOFTMAX) => { - let mut d = vec![0i64; c * h * w]; - let mut e = vec![0i128; w]; - for row in 0..c * h { - let r = &x.data[row * w..(row + 1) * w]; - let m = *r.iter().max().expect("a row has at least one element") as i128; - let mut sum: i128 = 0; - for (k, &v) in r.iter().enumerate() { - e[k] = exp_neg_q16(v as i128 - m); - sum += e[k]; - } - for k in 0..w { - d[row * w + k] = to64(((e[k] << 16) + (sum >> 1)) / sum, at)?; - } - } - one(Tensor::new(x.c, x.h, x.w, d)) - } - (_, SIGMOID) => one(map(x, at, |v| { - Some(if v >= 0 { - let e = exp_neg_q16(-v); - (1i128 << 32) / ((1 << 16) + e) - } else { - let e = exp_neg_q16(v); - (e << 16) / ((1 << 16) + e) - }) - })?), - (Params::Elu { alpha }, _) => one(map(x, at, |v| { - Some(if v > 0 { v } else { ((*alpha as i128).checked_mul(exp_neg_q16(v) - (1 << 16))?) >> 16 }) - })?), - (Params::Gram { groups, rq }, _) => { - let b = get(vals, op.ins[1]); - let d_ = c / *groups as usize; - let plane = h * w; - let mut d = vec![0i64; c * d_]; - for gi in 0..*groups as usize { - for i in 0..d_ { - for j in 0..d_ { - let (ca, cb) = (gi * d_ + i, gi * d_ + j); - let mut acc: i128 = 0; - for p in 0..plane { - let t = (x.data[ca * plane + p] as i128) * (b.data[cb * plane + p] as i128); - acc = acc.checked_add(t).ok_or(wide(at))?; - } - d[ca * d_ + j] = to64(round(acc, rq.shift(0), rq.round).ok_or(wide(at))?, at)?; - } - } - } - one(Tensor::new(x.c, 1, d_ as u32, d)) - } - (Params::Apply { groups, rq }, _) => { - let v = get(vals, op.ins[1]); - let d_ = c / *groups as usize; - let plane = v.h as usize * v.w as usize; - let mut d = vec![0i64; c * plane]; - for gi in 0..*groups as usize { - for i in 0..d_ { - for p in 0..plane { - let mut acc: i128 = 0; - for j in 0..d_ { - let t = (x.data[(gi * d_ + i) * d_ + j] as i128) * (v.data[(gi * d_ + j) * plane + p] as i128); - acc = acc.checked_add(t).ok_or(wide(at))?; - } - d[(gi * d_ + i) * plane + p] = to64(round(acc, rq.shift(0), rq.round).ok_or(wide(at))?, at)?; - } - } - } - one(Tensor::new(v.c, v.h, v.w, d)) + Ok(vec![Tensor::filled(out_c(0), x.h, x.w, v)]) } + (Params::Igdn { gf, frac, gamma, beta, .. }, _) => one(k_igdn(x, *gf, *frac, gamma, beta, at, obs)), + (Params::LayerNorm { eps, gamma, beta, .. }, _) => one(k_layernorm(x, *eps, gamma, beta, at, obs)), + (Params::L2norm { eps }, _) => one(k_l2norm(x, *eps, at, obs)), + (_, SOFTMAX) => one(k_softmax(x, at, obs)), + (_, SIGMOID) => one(k_sigmoid(x, at, obs)), + (Params::Elu { alpha }, _) => one(k_elu(x, *alpha, at, obs)), + (Params::Gram { groups, rq }, _) => one(k_gram(x, get(vals, op.ins[1]), u(*groups), rq, at, obs)), + (Params::Apply { groups, rq }, _) => one(k_apply(x, get(vals, op.ins[1]), u(*groups), rq, at, obs)), _ => Err(wide(at)), } } -fn crop(x: &Tensor, y0: usize, x0: usize, oh: usize, ow: usize) -> Tensor { +// Each operator's computation, on its input tensors, its parameters and its output +// sizes as the plan gives them (§5). `eval` dispatches to these; a model checker's +// harness calls one directly, with sizes and parameters it can see. + +/// `conv` (§5.2). +#[allow(clippy::too_many_arguments)] +pub(crate) fn k_conv( + x: &Tensor, cout: usize, kh: usize, kw: usize, sh: usize, sw: usize, ph: usize, pw: usize, groups: usize, rq: &Rq, wt: &[i64], oh: usize, + ow: usize, at: u32, obs: &mut O, +) -> Res { + let (c, h, w) = (x.c as usize, x.h as usize, x.w as usize); + let (cg, og) = (c / groups, cout / groups); + let mut d = vec![0i64; cout * oh * ow]; + for o in 0..cout { + let base = (o / og) * cg; + for y in 0..oh { + for xx in 0..ow { + let mut acc: i128 = 0; + for ci in 0..cg { + for i in 0..kh { + let iy = y * sh + i; + if iy < ph || iy - ph >= h { + continue; + } + for j in 0..kw { + let ix = xx * sw + j; + if ix < pw || ix - pw >= w { + continue; + } + let wv = wt[((o * cg + ci) * kh + i) * kw + j] as i128; + let term = wv * x.at(base + ci, iy - ph, ix - pw) as i128; + obs.see(at, "conv.term", term); + acc = acc.checked_add(term).ok_or(wide(at))?; + obs.see(at, "conv.acc", acc); + } + } + } + d[(o * oh + y) * ow + xx] = to64(rq_apply(rq, o, acc, at, obs).ok_or(wide(at))?, at)?; + } + } + } + Ok(Tensor::new(cout as u32, oh as u32, ow as u32, d)) +} + +/// `conv_transpose` (§5.3), in the scatter form: the same products as §5.3's gather, +/// summed exactly. +#[allow(clippy::too_many_arguments)] +pub(crate) fn k_conv_t( + x: &Tensor, cout: usize, kh: usize, kw: usize, sh: usize, sw: usize, ph: usize, pw: usize, oph: usize, opw: usize, rq: &Rq, wt: &[i64], + oh: usize, ow: usize, at: u32, obs: &mut O, +) -> Res { + let (c, h, w) = (x.c as usize, x.h as usize, x.w as usize); + let uh = (h - 1) * sh + kh + oph; + let uw = (w - 1) * sw + kw + opw; + let mut plane = vec![0i128; cout * uh * uw]; + for ci in 0..c { + for u in 0..h { + for v in 0..w { + let xv = x.at(ci, u, v) as i128; + if xv == 0 { + continue; + } + for o in 0..cout { + for i in 0..kh { + let row = (o * uh + u * sh + i) * uw + v * sw; + for j in 0..kw { + let wv = wt[((ci * cout + o) * kh + i) * kw + j] as i128; + obs.see(at, "convT.term", wv * xv); + let cell = &mut plane[row + j]; + *cell = cell.checked_add(wv * xv).ok_or(wide(at))?; + obs.see(at, "convT.acc", *cell); + } + } + } + } + } + } + let mut d = vec![0i64; cout * oh * ow]; + for o in 0..cout { + for y in 0..oh { + for xx in 0..ow { + let acc = plane[(o * uh + y + ph) * uw + xx + pw]; + d[(o * oh + y) * ow + xx] = to64(rq_apply(rq, o, acc, at, obs).ok_or(wide(at))?, at)?; + } + } + } + Ok(Tensor::new(cout as u32, oh as u32, ow as u32, d)) +} + +/// `rescale` (§5.4). +pub(crate) fn k_rescale(x: &Tensor, rq: &Rq, at: u32, obs: &mut O) -> Res { + map_c(x, at, |o, v| rq_apply(rq, o, v, at, obs)) +} + +/// `chscale` (§5.4), with `row` the value of its scalar. +pub(crate) fn k_chscale(x: &Tensor, row: usize, r: Round, shift: u32, m: &[i64], at: u32, obs: &mut O) -> Res { + let c = x.c as usize; + map_c(x, at, |o, v| { + obs.see(at, "rq.t", v); + let p = v.checked_mul(m[row * c + o] as i128)?; + see_p(obs, at, p, shift, r); + let q = round(p, shift, r)?; + obs.see(at, "rq.q", q); + obs.see(at, "rq.y", q); + Some(q) + }) +} + +/// `mul` (§5.4). +pub(crate) fn k_mul(x: &Tensor, b: &Tensor, rq: &Rq, at: u32, obs: &mut O) -> Res { + let (c, plane) = (x.c as usize, x.h as usize * x.w as usize); + let mut d = Vec::with_capacity(x.data.len()); + for o in 0..c { + let bo = if b.c as usize == c { o } else { 0 }; + for k in 0..plane { + let p = (x.data[o * plane + k] as i128) * (b.data[bo * plane + k] as i128); + obs.see(at, "mul.p", p); + d.push(to64(rq_apply(rq, o, p, at, obs).ok_or(wide(at))?, at)?); + } + } + Ok(Tensor::new(x.c, x.h, x.w, d)) +} + +/// `lut16` (§5.6). +pub(crate) fn k_lut16(x: &Tensor, t: &[i16], at: u32) -> Res { + map(x, at, |v| { + let i = v + 32768; + if (0..65536).contains(&i) { Some(t[i as usize] as i128) } else { None } + }) +} + +/// `add` (§5.5). +pub(crate) fn k_add(x: &Tensor, b: &Tensor, at: u32) -> Res { + let mut d = Vec::with_capacity(x.data.len()); + for (&p, &q) in x.data.iter().zip(&b.data) { + d.push(to64(p as i128 + q as i128, at)?); + } + Ok(Tensor::new(x.c, x.h, x.w, d)) +} + +/// `concat` (§5.10). +pub(crate) fn k_concat(ins: &[&Tensor], out_c: u32) -> Tensor { + let mut d = Vec::new(); + for t in ins { + d.extend_from_slice(&t.data); + } + Tensor::new(out_c, ins[0].h, ins[0].w, d) +} + +/// `chunk_add` (§5.5). +pub(crate) fn k_chunk_add(x: &Tensor, at: u32) -> Res { + let half = (x.c as usize / 2) * x.h as usize * x.w as usize; + let mut d = Vec::with_capacity(half); + for k in 0..half { + d.push(to64(x.data[k] as i128 + x.data[k + half] as i128, at)?); + } + Ok(Tensor::new(x.c / 2, x.h, x.w, d)) +} + +/// `split` (§5.10). +pub(crate) fn k_split(x: &Tensor, start: usize, count: u32) -> Tensor { + let plane = x.h as usize * x.w as usize; + let s = start * plane; + Tensor::new(count, x.h, x.w, x.data[s..s + count as usize * plane].to_vec()) +} + +/// `pixel_shuffle` (§5.10). +pub(crate) fn k_pixel_shuffle(x: &Tensor, r: usize, oh: usize, ow: usize) -> Tensor { + let (c, h, w) = (x.c as usize, x.h as usize, x.w as usize); + let co = c / (r * r); + let mut d = vec![0i64; c * h * w]; + for cc in 0..co { + for y in 0..h { + for xx in 0..w { + for i in 0..r { + for j in 0..r { + d[(cc * oh + y * r + i) * ow + xx * r + j] = x.at(cc * r * r + i * r + j, y, xx); + } + } + } + } + } + Tensor::new(co as u32, oh as u32, ow as u32, d) +} + +/// `pixel_unshuffle` (§5.10). +pub(crate) fn k_pixel_unshuffle(x: &Tensor, r: usize, oh: usize, ow: usize) -> Tensor { + let (c, h, w) = (x.c as usize, x.h as usize, x.w as usize); + let mut d = vec![0i64; c * h * w]; + for cc in 0..c { + for y in 0..oh { + for xx in 0..ow { + for i in 0..r { + for j in 0..r { + d[((cc * r * r + i * r + j) * oh + y) * ow + xx] = x.at(cc, y * r + i, xx * r + j); + } + } + } + } + } + Tensor::new((c * r * r) as u32, oh as u32, ow as u32, d) +} + +/// `leaky` (§5.5). +pub(crate) fn k_leaky(x: &Tensor, a: i64, f: u32, at: u32, obs: &mut O) -> Res { + map(x, at, |v| { + Some(if v >= 0 { + v + } else { + obs.see(at, "leaky.p", v * a as i128); + (v * a as i128) >> f + }) + }) +} + +/// `pad_rep` (§5.10). +pub(crate) fn k_pad_rep(x: &Tensor, oh: usize, ow: usize) -> Tensor { + let (c, h, w) = (x.c as usize, x.h as usize, x.w as usize); + let mut d = Vec::with_capacity(c * oh * ow); + for cc in 0..c { + for y in 0..oh { + for xx in 0..ow { + d.push(x.at(cc, y.min(h - 1), xx.min(w - 1))); + } + } + } + Tensor::new(x.c, oh as u32, ow as u32, d) +} + +/// `subpos_split` (§5.10). +pub(crate) fn k_subpos_split(x: &Tensor, order: &[u8; 4], oh: usize, ow: usize) -> Vec { + let c = x.c as usize; + let mut outs = Vec::with_capacity(4); + for &o in order { + let (a, b) = ((o >> 1) as usize, (o & 1) as usize); + let mut d = Vec::with_capacity(c * oh * ow); + for cc in 0..c { + for y in 0..oh { + for xx in 0..ow { + d.push(x.at(cc, 2 * y + a, 2 * xx + b)); + } + } + } + outs.push(Tensor::new(x.c, oh as u32, ow as u32, d)); + } + outs +} + +/// `subpos_merge` (§5.10). +pub(crate) fn k_subpos_merge(ins: &[&Tensor], order: &[u8; 4], oh: usize, ow: usize) -> Tensor { + let (c, h, w) = (ins[0].c as usize, ins[0].h as usize, ins[0].w as usize); + let mut d = vec![0i64; c * oh * ow]; + for (k, &o) in order.iter().enumerate() { + let (a, b) = ((o >> 1) as usize, (o & 1) as usize); + let t = ins[k]; + for cc in 0..c { + for y in 0..h { + for xx in 0..w { + d[(cc * oh + 2 * y + a) * ow + 2 * xx + b] = t.at(cc, y, xx); + } + } + } + } + Tensor::new(ins[0].c, oh as u32, ow as u32, d) +} + +/// `igdn` (§5.7). +pub(crate) fn k_igdn(x: &Tensor, gf: u32, frac: u32, gamma: &[i64], beta: &[i64], at: u32, obs: &mut O) -> Res { + let (c, h, w) = (x.c as usize, x.h as usize, x.w as usize); + let mut d = vec![0i64; c * h * w]; + let plane = h * w; + let mut x2 = vec![0i128; c]; + for p in 0..plane { + for j in 0..c { + let v = x.data[j * plane + p] as i128; + x2[j] = v * v; + obs.see(at, "igdn.x2", x2[j]); + } + for i in 0..c { + let mut n = beta[i] as i128; + obs.see(at, "igdn.N", n); + for j in 0..c { + let gx2 = (gamma[i * c + j] as i128).checked_mul(x2[j]).ok_or(wide(at))?; + obs.see(at, "igdn.gx2", gx2); + obs.see(at, "igdn.term", gx2 >> gf); + n = n.checked_add(gx2 >> gf).ok_or(wide(at))?; + obs.see(at, "igdn.N", n); + } + let r = (n.max(0) as u128).isqrt() as i128; + obs.see(at, "igdn.r", r); + let xr = (x.data[i * plane + p] as i128).checked_mul(r).ok_or(wide(at))?; + obs.see(at, "igdn.xr", xr); + d[i * plane + p] = to64(xr >> frac, at)?; + } + } + Ok(Tensor::new(x.c, x.h, x.w, d)) +} + +/// `layernorm_c` (§5.7). +pub(crate) fn k_layernorm(x: &Tensor, eps: u64, gamma: &[i64], beta: &[i64], at: u32, obs: &mut O) -> Res { + let (c, plane) = (x.c as usize, x.h as usize * x.w as usize); + let mut d = vec![0i64; c * plane]; + let ci = c as i128; + for p in 0..plane { + let mut s: i128 = 0; + for k in 0..c { + s = s.checked_add(x.data[k * plane + p] as i128).ok_or(wide(at))?; + obs.see(at, "ln.S", s); + } + let m_num = s.checked_add((ci / 2) * s.signum()).ok_or(wide(at))?; + obs.see(at, "ln.m", m_num); + let m = m_num / ci; + let mut t: i128 = 0; + let mut dev = vec![0i128; c]; + for k in 0..c { + let dk = (x.data[k * plane + p] as i128) - m; + obs.see(at, "ln.d", dk); + dev[k] = dk; + t = t.checked_add(dk.checked_mul(dk).ok_or(wide(at))?).ok_or(wide(at))?; + obs.see(at, "ln.T", t); + } + let v = t / ci; + let u = v.checked_add(eps as i128).ok_or(wide(at))?; + obs.see(at, "ln.v", u); + let k = rsqrt_q16(u as u128); + obs.see(at, "rsq.num", 1 << 32); + obs.see(at, "ln.k", k); + for kk in 0..c { + let dk = dev[kk].checked_mul(k).ok_or(wide(at))?; + obs.see(at, "ln.dk", dk); + let n = dk >> 16; + obs.see(at, "ln.n", n); + let ng = n.checked_mul(gamma[kk] as i128).ok_or(wide(at))?; + obs.see(at, "ln.ng", ng); + d[kk * plane + p] = to64((ng >> 16).checked_add(beta[kk] as i128).ok_or(wide(at))?, at)?; + } + } + Ok(Tensor::new(x.c, x.h, x.w, d)) +} + +/// `l2norm` (§5.7). +pub(crate) fn k_l2norm(x: &Tensor, eps: u64, at: u32, obs: &mut O) -> Res { + let (c, plane) = (x.c as usize, x.h as usize * x.w as usize); + let mut d = vec![0i64; c * plane]; + for cc in 0..c { + let mut t: i128 = 0; + for p in 0..plane { + let v = x.data[cc * plane + p] as i128; + t = t.checked_add(v * v).ok_or(wide(at))?; + obs.see(at, "l2.T", t); + } + let u = t.checked_add(eps as i128).ok_or(wide(at))?; + obs.see(at, "l2.T", u); + let k = rsqrt_q16(u as u128); + obs.see(at, "rsq.num", 1 << 32); + obs.see(at, "l2.k", k); + for p in 0..plane { + let vk = (x.data[cc * plane + p] as i128).checked_mul(k).ok_or(wide(at))?; + obs.see(at, "l2.vk", vk); + d[cc * plane + p] = to64(vk >> 16, at)?; + } + } + Ok(Tensor::new(x.c, x.h, x.w, d)) +} + +/// `softmax` (§5.7). +pub(crate) fn k_softmax(x: &Tensor, at: u32, obs: &mut O) -> Res { + let (c, h, w) = (x.c as usize, x.h as usize, x.w as usize); + let mut d = vec![0i64; c * h * w]; + let mut e = vec![0i128; w]; + for row in 0..c * h { + let r = &x.data[row * w..(row + 1) * w]; + let m = *r.iter().max().expect("a row has at least one element") as i128; + let mut sum: i128 = 0; + for (k, &v) in r.iter().enumerate() { + obs.see(at, "sm.diff", v as i128 - m); + e[k] = exp_observed(v as i128 - m, at, obs); + sum += e[k]; + obs.see(at, "sm.sum", sum); + } + for k in 0..w { + obs.see(at, "sm.num", (e[k] << 16) + (sum >> 1)); + d[row * w + k] = to64(((e[k] << 16) + (sum >> 1)) / sum, at)?; + } + } + Ok(Tensor::new(x.c, x.h, x.w, d)) +} + +/// `sigmoid` (§5.8). +pub(crate) fn k_sigmoid(x: &Tensor, at: u32, obs: &mut O) -> Res { + map(x, at, |v| { + Some(if v >= 0 { + let e = exp_observed(-v, at, obs); + obs.see(at, "sig.num", 1i128 << 32); + (1i128 << 32) / ((1 << 16) + e) + } else { + let e = exp_observed(v, at, obs); + obs.see(at, "sig.num", e << 16); + (e << 16) / ((1 << 16) + e) + }) + }) +} + +/// `elu` (§5.8). +pub(crate) fn k_elu(x: &Tensor, alpha: i64, at: u32, obs: &mut O) -> Res { + map(x, at, |v| { + Some(if v > 0 { + v + } else { + let p = (alpha as i128).checked_mul(exp_observed(v, at, obs) - (1 << 16))?; + obs.see(at, "elu.p", p); + p >> 16 + }) + }) +} + +/// `gram` (§5.9). +pub(crate) fn k_gram(x: &Tensor, b: &Tensor, groups: usize, rq: &Rq, at: u32, obs: &mut O) -> Res { + let c = x.c as usize; + let d_ = c / groups; + let plane = x.h as usize * x.w as usize; + let mut d = vec![0i64; c * d_]; + for gi in 0..groups { + for i in 0..d_ { + for j in 0..d_ { + let (ca, cb) = (gi * d_ + i, gi * d_ + j); + let mut acc: i128 = 0; + for p in 0..plane { + let t = (x.data[ca * plane + p] as i128) * (b.data[cb * plane + p] as i128); + obs.see(at, "gram.term", t); + acc = acc.checked_add(t).ok_or(wide(at))?; + obs.see(at, "gram.acc", acc); + } + d[ca * d_ + j] = to64(rq_apply(rq, 0, acc, at, obs).ok_or(wide(at))?, at)?; + } + } + } + Ok(Tensor::new(x.c, 1, d_ as u32, d)) +} + +/// `apply` (§5.9). +pub(crate) fn k_apply(x: &Tensor, v: &Tensor, groups: usize, rq: &Rq, at: u32, obs: &mut O) -> Res { + let c = x.c as usize; + let d_ = c / groups; + let plane = v.h as usize * v.w as usize; + let mut d = vec![0i64; c * plane]; + for gi in 0..groups { + for i in 0..d_ { + for p in 0..plane { + let mut acc: i128 = 0; + for j in 0..d_ { + let t = (x.data[(gi * d_ + i) * d_ + j] as i128) * (v.data[(gi * d_ + j) * plane + p] as i128); + obs.see(at, "apply.term", t); + acc = acc.checked_add(t).ok_or(wide(at))?; + obs.see(at, "apply.acc", acc); + } + d[(gi * d_ + i) * plane + p] = to64(rq_apply(rq, 0, acc, at, obs).ok_or(wide(at))?, at)?; + } + } + } + Ok(Tensor::new(v.c, v.h, v.w, d)) +} + +/// `crop` and `crop_to` (§5.10). +pub(crate) fn crop(x: &Tensor, y0: usize, x0: usize, oh: usize, ow: usize) -> Tensor { let mut d = Vec::with_capacity(x.c as usize * oh * ow); for cc in 0..x.c as usize { for y in 0..oh { @@ -597,7 +816,7 @@ mod tests { assert_eq!(round(i128::MAX, 127, Round::Floor), Some(0)); assert_eq!(round(-(1 << 126), 127, Round::HalfEven), Some(0)); // p + 2^(s−1) = 2^127 leaves i128: rq.p's interval fails its class under acc64, - // so no certified graph forms it, and the uncertified run refuses. + // so no certified graph forms it, and `round` says so. assert_eq!(round(1 << 126, 127, Round::HalfUp), None); assert_eq!(round((1 << 126) - 1, 127, Round::HalfUp), Some(0)); } diff --git a/wai/wai-ops/src/lib.rs b/wai/wai-ops/src/lib.rs index c37396bae..5df059449 100644 --- a/wai/wai-ops/src/lib.rs +++ b/wai/wai-ops/src/lib.rs @@ -8,27 +8,32 @@ //! - [`interp`]: the reference interpreter of the graph operators (§5). //! - [`stage`]: the stage operators E1–E13 (§5E). //! - [`lower`]: the canonical lowerings of §13. +//! - [`limb32`]: a reference model of a 32-bit fabric's `acc32` products and epilogue. +//! - [`bounds`]: load step 8, the bounds pass (§8.1–§8.3), the verdict and the bounds +//! certificate (§8.5), and admissible ranges (§8.4). //! - [`vectors`]: the conformance vector files of §14.1, recomputed from their inputs. //! - [`generate`]: the generator of `../ops-conformance/`, which writes those files. //! -//! Every value is an exact integer. Nothing here uses floating point, wraps, or -//! depends on the target's word size. +//! Every value is an exact integer. Nothing here uses floating point or depends on the +//! target's word size, and nothing wraps except in [`limb32`], whose wrapping 32-bit +//! adds are the fabric's it models, and are proved to give the exact values. //! -//! **Load step 8**, the bounds pass and the profile verdict (§8, §10.5 step 8), is -//! not built yet. Without the `uncertified` feature a graph never completes its load; -//! with it, step 8 is skipped. See [`graph::load`]. The interpreter runs only a -//! [`Loaded`] graph, which only `load` makes, so no entry point decodes past step 8. +//! A graph loads under a profile ([`graph::load`]): load step 8 runs the bounds pass +//! and refuses a graph whose verdict does not meet that profile (§8.6). The +//! interpreter runs only a [`Loaded`] graph, which only `load` makes, so no entry +//! point decodes a graph its certificate does not admit. #![no_std] #![forbid(unsafe_code)] extern crate alloc; +pub mod bounds; pub mod code; -#[cfg(feature = "uncertified")] pub mod generate; pub mod graph; pub mod interp; pub mod json; +pub mod limb32; pub mod lower; pub mod plan; pub mod sha256; @@ -36,6 +41,12 @@ pub mod stage; pub mod vectors; pub mod xint; +// The model checker's harnesses (K1–K33 of the test plan) are in `src/proofs/`, behind +// `#[cfg(kani)]`. `wai-verify` hosts them: it includes this crate's modules by +// `#[path]`, beside the `wai-rs` sources one of them is checked against, so they are +// compiled there and not here. + +pub use bounds::Profile; pub use code::{Code, Refusal, Site}; pub use graph::{Graph, Loaded}; pub use interp::{Sequence, Tensor, run}; diff --git a/wai/wai-ops/src/limb32.rs b/wai/wai-ops/src/limb32.rs new file mode 100644 index 000000000..d2dfbce10 --- /dev/null +++ b/wai/wai-ops/src/limb32.rs @@ -0,0 +1,201 @@ +//! The arithmetic of a 32-bit integer fabric for `acc32`'s two `product` +//! intermediates (§7.1, §7.3): a signed 32 × 32-bit product formed from 16-bit halves +//! in unsigned 32-bit arithmetic that wraps, and the requantisation epilogue on that +//! two-word value — the rounding shift, the `post` bias, and the narrowing to `i32`. +//! +//! This is a reference model for a shader. It uses only what a 32-bit integer shading +//! language has: `u32` addition, subtraction and multiplication that wrap, bitwise +//! operations, comparisons, and shifts whose amount is taken modulo 32. So every shift +//! by 32 or more is handled explicitly (§6), and a signed value is a `u32`'s bits read +//! as `i32`. Kani's K2 and K2b check it against the definitions; the unit tests below +//! check it at the edges. + +use crate::graph::Round; + +/// A 64-bit two's-complement value as two 32-bit words. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct W64 { + pub hi: u32, + pub lo: u32, +} + +impl W64 { + pub const fn from_i64(v: i64) -> W64 { + W64 { hi: (v >> 32) as u32, lo: v as u32 } + } + pub const fn to_i64(self) -> i64 { + (((self.hi as u64) << 32) | self.lo as u64) as i64 + } +} + +// Shifts as a 32-bit shading language performs them: the amount is taken mod 32. +fn shl(x: u32, k: u32) -> u32 { + x.wrapping_shl(k) +} +fn shr(x: u32, k: u32) -> u32 { + x.wrapping_shr(k) +} +/// An arithmetic shift right of a word read as `i32`. +fn sar(x: u32, k: u32) -> u32 { + (x as i32).wrapping_shr(k) as u32 +} + +/// `a + b`, modulo 2^64. +pub fn add(a: W64, b: W64) -> W64 { + let lo = a.lo.wrapping_add(b.lo); + let carry = (lo < a.lo) as u32; + W64 { hi: a.hi.wrapping_add(b.hi).wrapping_add(carry), lo } +} + +/// `−a`, modulo 2^64. +pub fn neg(a: W64) -> W64 { + add(W64 { hi: !a.hi, lo: !a.lo }, W64 { hi: 0, lo: 1 }) +} + +/// The products of the 16-bit halves of `a = a1·2^16 + a0` and `b = b1·2^16 + b0`: +/// `[a0·b0, a0·b1, a1·b0, a1·b1]`. Each is at most `(2^16 − 1)² < 2^32`, so none wraps. +pub fn partials(a: u32, b: u32) -> [u32; 4] { + let (a0, a1, b0, b1) = (a & 0xFFFF, a >> 16, b & 0xFFFF, b >> 16); + [a0 * b0, a0 * b1, a1 * b0, a1 * b1] +} + +/// `p00 + (p01 + p10)·2^16 + p11·2^32` as two words, with the carries of 32-bit adds. +pub fn combine(p: [u32; 4]) -> W64 { + let [p00, p01, p10, p11] = p; + let mid = p01.wrapping_add(p10); + let c1 = (mid < p01) as u32; + let mid2 = mid.wrapping_add(p00 >> 16); + let c2 = (mid2 < mid) as u32; + let lo = shl(mid2, 16) | (p00 & 0xFFFF); + let hi = p11.wrapping_add(shr(mid2, 16)).wrapping_add(shl(c1 + c2, 16)); + W64 { hi, lo } +} + +/// The unsigned product of two 32-bit values. +pub fn mul_u32(a: u32, b: u32) -> W64 { + combine(partials(a, b)) +} + +/// `|a|` as a `u32`: `2^31` for `a = −2^31`. +pub fn magnitude(a: i32) -> u32 { + if a < 0 { (a as u32).wrapping_neg() } else { a as u32 } +} + +/// The signed product of two `i32`, `rq.p` under `acc32`: the product of the +/// magnitudes, negated when exactly one operand is negative. +pub fn mul_i32(a: i32, b: i32) -> W64 { + let m = mul_u32(magnitude(a), magnitude(b)); + if (a < 0) != (b < 0) { neg(m) } else { m } +} + +/// `2^k` as two words, for `k` in `0..=63` (`2^63` is the bit pattern of `−2^63`). +fn pow2(k: u32) -> W64 { + if k < 32 { W64 { hi: 0, lo: shl(1, k) } } else { W64 { hi: shl(1, k - 32), lo: 0 } } +} + +/// `⌊p / 2^s⌋`, for `s` in `0..=63`. +pub fn floor_shift(p: W64, s: u32) -> W64 { + if s == 0 { + p + } else if s < 32 { + W64 { hi: sar(p.hi, s), lo: shr(p.lo, s) | shl(p.hi, 32 - s) } + } else { + W64 { hi: sar(p.hi, 31), lo: sar(p.hi, s - 32) } + } +} + +/// `R_round(p, s)` (§2) on two words, for `s` in `0..=63`. `half_up` forms +/// `p + 2^(s−1)`, which `rq.p`'s interval holds, so under `acc32` it fits i64. +pub fn round(p: W64, s: u32, r: Round) -> W64 { + if s == 0 { + return p; + } + match r { + Round::Floor => floor_shift(p, s), + Round::HalfUp => floor_shift(add(p, pow2(s - 1)), s), + Round::HalfEven => { + let q = floor_shift(p, s); + // The remainder p − q·2^s is p's low s bits; it and h = 2^(s−1) are + // non-negative and below 2^63, so they compare as unsigned pairs. + let mask = add(pow2(s), W64 { hi: u32::MAX, lo: u32::MAX }); + let rem = W64 { hi: p.hi & mask.hi, lo: p.lo & mask.lo }; + let h = pow2(s - 1); + let above = rem.hi > h.hi || (rem.hi == h.hi && rem.lo > h.lo); + if above || (rem == h && q.lo & 1 == 1) { add(q, W64 { hi: 0, lo: 1 }) } else { q } + } + } +} + +/// The requantisation epilogue on a product `p`, for `s` in `0..=63`: +/// `R_round(p, s) + post`, narrowed to `i32`. The bias is added on two words, so the +/// result is exact whenever `rq.y` fits i32, which `acc32` certifies. +pub fn epilogue(p: W64, s: u32, r: Round, post: i32) -> i32 { + let y = add(round(p, s, r), W64::from_i64(post as i64)); + y.lo as i32 +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::interp; + + const EDGES: [i32; 12] = [0, 1, -1, 2, -2, 0xFFFF, 0x10000, -0x10000, i32::MAX, i32::MIN, i32::MAX - 1, i32::MIN + 1]; + + /// Whether `rq.p`'s second value, `p + 2^(s−1)` under `half_up`, fits i64, as `acc32` + /// requires of every product it certifies. + fn addend_fits(p: i64, s: u32, r: Round) -> bool { + r != Round::HalfUp || s == 0 || p as i128 + (1i128 << (s - 1)) <= i64::MAX as i128 + } + + fn lcg(s: &mut u64) -> u64 { + *s = s.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + *s >> 16 + } + + #[test] + fn product_matches_i64() { + for &a in &EDGES { + for &b in &EDGES { + assert_eq!(mul_i32(a, b).to_i64(), a as i64 * b as i64, "{a} × {b}"); + } + } + let mut s = 1u64; + for _ in 0..200_000 { + let (a, b) = (lcg(&mut s) as i32, lcg(&mut s) as i32); + assert_eq!(mul_i32(a, b).to_i64(), a as i64 * b as i64, "{a} × {b}"); + } + } + + #[test] + fn epilogue_matches_the_definitions() { + let mut s = 7u64; + let rounds = [Round::Floor, Round::HalfUp, Round::HalfEven]; + for k in 0..400_000u64 { + let (a, b) = (lcg(&mut s) as i32, lcg(&mut s) as i32); + let p = a as i64 * b as i64; + let sh = (lcg(&mut s) % 64) as u32; + let r = rounds[(k % 3) as usize]; + let post = (lcg(&mut s) as i32) >> (lcg(&mut s) % 32); + if !addend_fits(p, sh, r) { + continue; + } + let q = interp::round(p as i128, sh, r).unwrap(); + let y = q + post as i128; + if i32::try_from(y).is_ok() { + assert_eq!(epilogue(mul_i32(a, b), sh, r, post) as i128, y, "{a} × {b}, s {sh}, {r:?}, post {post}"); + } + } + // The ties of each rounding, at every shift. + for sh in 1..64u32 { + for &r in &rounds { + for &p in &[3i64.wrapping_shl(sh - 1), -(3i64.wrapping_shl(sh - 1)), 1i64 << (sh - 1), -(1i64 << (sh - 1))] { + if !addend_fits(p, sh, r) { + continue; + } + let q = interp::round(p as i128, sh, r).unwrap(); + assert_eq!(round(W64::from_i64(p), sh, r).to_i64() as i128, q, "p {p}, s {sh}, {r:?}"); + } + } + } + } +} diff --git a/wai/wai-ops/src/lower/mod.rs b/wai/wai-ops/src/lower/mod.rs index 1299d09f8..702abbf7f 100644 --- a/wai/wai-ops/src/lower/mod.rs +++ b/wai/wai-ops/src/lower/mod.rs @@ -17,6 +17,8 @@ mod whm; pub use jpegai::jpegai; pub use synth::int_synth; pub use whm::{Net, NetLayer, int_hyper, parse_wam1, parse_whm1, splat, wam1, whm1, wmb1, world}; +#[cfg(kani)] +pub(crate) use whm::{p_conv, p_igdn, p_leaky}; /// A lowered set: its graphs by role, in §13.0's order. #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/wai/wai-ops/src/lower/whm.rs b/wai/wai-ops/src/lower/whm.rs index 2427896ac..d3833782a 100644 --- a/wai/wai-ops/src/lower/whm.rs +++ b/wai/wai-ops/src/lower/whm.rs @@ -138,41 +138,52 @@ fn maxabs(v: &[i64]) -> I512 { const I64: I512 = I512::from_i128(i64::MAX as i128); const I128: I512 = I512::from_i128(i128::MAX); +/// `P_ℓ(X)` for a layer of tag 0 or 1 (§13.2): `c·k·k·Wm·X ≤ I64` and +/// `⌊c·k·k·Wm·X·Mm / 2^shift⌋ + 1 + Bm ≤ I64`, with `terms = c·k·k` (`c·k` for `WAM1`). +pub(crate) fn p_conv(terms: I512, wm: I512, mm: I512, bm: I512, shift: u32, x: u128) -> bool { + let a = terms.mul(wm).mul(I512::from_u128(x)); + a <= I64 && a.mul(mm).shr_floor(shift).add(I512::ONE).add(bm) <= I64 +} + +/// `P_ℓ(X)` for a layer of tag 2 (§13.2): `G·X² ≤ I128`; +/// `N = Bb + c·(⌊G·X²/2^gf⌋ + 1) ≤ I128`; `isqrt(N) ≤ I64`; +/// `⌊X·isqrt(N) / 2^afrac⌋ + 1 ≤ I64`. +pub(crate) fn p_igdn(g: I512, bb: I512, cc: I512, gf: u32, af: u32, x: u128) -> bool { + let x = I512::from_u128(x); + let gx2 = g.mul(x).mul(x); + if gx2 > I128 { + return false; + } + let n = bb.add(cc.mul(gx2.shr_floor(gf).add(I512::ONE))); + if n > I128 { + return false; + } + let r = n.isqrt(); + r <= I64 && x.mul(r).shr_floor(af).add(I512::ONE) <= I64 +} + +/// `P_ℓ(X)` for a layer of tag 4 (§13.2): `X·|slope_q| ≤ I64`. +pub(crate) fn p_leaky(a: I512, x: u128) -> bool { + I512::from_u128(x).mul(a) <= I64 +} + /// `X_ℓ` for a layer reading `c` channels (§13.2), or `None` for a layer no `check` /// range precedes (a ReLU). Refuses when `P_ℓ(0)` fails. fn x_of(net: &Net, l: &NetLayer, c: u32) -> Res> { - let le = |a: I512, b: I512| a <= b; let x = match l { NetLayer::ConvT { k, w, mult, bias, .. } | NetLayer::Conv { k, w, mult, bias, .. } => { let kk = if net.audio { *k as u64 } else { *k as u64 * *k as u64 }; let terms = I512::from_u64(c as u64).mul(I512::from_u64(kk)); let (wm, mm, bm) = (maxabs(w), maxabs(mult), maxabs(bias)); - let s = net.shift; - largest(|x| { - let a = terms.mul(wm).mul(I512::from_u128(x)); - le(a, I64) && le(a.mul(mm).shr_floor(s).add(I512::ONE).add(bm), I64) - }) + largest(|x| p_conv(terms, wm, mm, bm, net.shift, x)) } NetLayer::Igdn { gamma, beta, .. } => { let (g, bb, cc) = (maxabs(gamma), maxabs(beta), I512::from_u64(c as u64)); - let (gf, af) = (net.gf, net.afrac); - largest(|x| { - let x = I512::from_u128(x); - let gx2 = g.mul(x).mul(x); - if !le(gx2, I128) { - return false; - } - let n = bb.add(cc.mul(gx2.shr_floor(gf).add(I512::ONE))); - if !le(n, I128) { - return false; - } - let r = n.isqrt(); - le(r, I64) && le(x.mul(r).shr_floor(af).add(I512::ONE), I64) - }) + largest(|x| p_igdn(g, bb, cc, net.gf, net.afrac, x)) } NetLayer::Leaky { slope_q, .. } => { let a = I512::from_i128((*slope_q as i128).abs()); - largest(|x| le(I512::from_u128(x).mul(a), I64)) + largest(|x| p_leaky(a, x)) } NetLayer::Relu => return Ok(None), }; diff --git a/wai/wai-ops/src/plan.rs b/wai/wai-ops/src/plan.rs index e37327249..2ffada497 100644 --- a/wai/wai-ops/src/plan.rs +++ b/wai/wai-ops/src/plan.rs @@ -30,8 +30,8 @@ enum Mode<'a> { /// The sizes `(H, W)` of every tensor, indexed by tensor. pub type Sizes = Vec<(u64, u64)>; -#[derive(Clone, Copy)] -enum Fail { +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum Fail { Big, Shape, } @@ -46,6 +46,58 @@ fn capped(v: u64) -> Result { if v > CAP { Err(Fail::Big) } else { Ok(v) } } +/// `conv`'s output sides (§5.2): the padded sides are capped first. +#[allow(clippy::too_many_arguments)] +pub(crate) fn conv_sides(h: u64, w: u64, kh: u64, kw: u64, sh: u64, sw: u64, ph: u64, pw: u64) -> Result<(u64, u64), Fail> { + let hp = capped(add(h, mul(2, ph)?)?)?; + let wp = capped(add(w, mul(2, pw)?)?)?; + if hp < kh || wp < kw { + return Err(Fail::Shape); + } + Ok(((hp - kh) / sh + 1, (wp - kw) / sw + 1)) +} + +/// `conv_transpose`'s output sides (§5.3): the uncropped sides and the uncropped +/// output of `cout` planes are capped first. +#[allow(clippy::too_many_arguments)] +pub(crate) fn conv_t_sides(h: u64, w: u64, cout: u64, kh: u64, kw: u64, sh: u64, sw: u64, ph: u64, pw: u64, oph: u64, opw: u64) -> Result<(u64, u64), Fail> { + let uh = capped(add(add(mul(h - 1, sh)?, kh)?, oph)?)?; + let uw = capped(add(add(mul(w - 1, sw)?, kw)?, opw)?)?; + capped(mul(mul(cout, uh)?, uw)?)?; + let (ch2, cw2) = (2 * ph, 2 * pw); + if uh <= ch2 || uw <= cw2 { + return Err(Fail::Shape); + } + Ok((uh - ch2, uw - cw2)) +} + +/// `pixel_shuffle`'s output sides (§5.10). +pub(crate) fn shuffle_sides(h: u64, w: u64, r: u64) -> Result<(u64, u64), Fail> { + Ok((capped(mul(h, r)?)?, capped(mul(w, r)?)?)) +} + +/// `pixel_unshuffle`'s output sides (§5.10). +pub(crate) fn unshuffle_sides(h: u64, w: u64, r: u64) -> Result<(u64, u64), Fail> { + if h % r != 0 || w % r != 0 { + return Err(Fail::Shape); + } + Ok((h / r, w / r)) +} + +/// `pad_rep`'s output sides (§5.10). +pub(crate) fn pad_rep_sides(h: u64, w: u64, m: u64) -> Result<(u64, u64), Fail> { + Ok((capped(mul(h.div_ceil(m), m)?)?, capped(mul(w.div_ceil(m), m)?)?)) +} + +/// `crop`'s output side along one axis at run time (§5.10): the start `s0` and the +/// length `l` against the input's side `n`. +pub(crate) fn crop_side(s0: i128, l: i128, n: u64) -> Result { + if s0 < 0 || l < 1 || s0 + l > n as i128 { + return Err(Fail::Shape); + } + Ok(l as u64) +} + /// One operator's output sizes from its inputs' sizes. fn op_sizes(g: &Graph, op: &crate::graph::Op, hw: &[(u64, u64)], mode: Mode) -> Result, Fail> { let (h, w) = hw[op.ins[0] as usize]; @@ -54,22 +106,12 @@ fn op_sizes(g: &Graph, op: &crate::graph::Op, hw: &[(u64, u64)], mode: Mode) -> let shape = Err(Fail::Shape); Ok(match (&op.p, op.code) { (Params::Conv { kh, kw, sh, sw, ph, pw, .. }, _) => { - let hp = capped(add(h, mul(2, *ph as u64)?)?)?; - let wp = capped(add(w, mul(2, *pw as u64)?)?)?; - if hp < *kh as u64 || wp < *kw as u64 { - return shape; - } - vec![((hp - *kh as u64) / *sh as u64 + 1, (wp - *kw as u64) / *sw as u64 + 1)] + let u = |v: &u32| *v as u64; + vec![conv_sides(h, w, u(kh), u(kw), u(sh), u(sw), u(ph), u(pw))?] } (Params::ConvT { cout, kh, kw, sh, sw, ph, pw, oph, opw, .. }, _) => { - let uh = capped(add(add(mul(h - 1, *sh as u64)?, *kh as u64)?, *oph as u64)?)?; - let uw = capped(add(add(mul(w - 1, *sw as u64)?, *kw as u64)?, *opw as u64)?)?; - capped(mul(mul(*cout as u64, uh)?, uw)?)?; - let (ch2, cw2) = (2 * *ph as u64, 2 * *pw as u64); - if uh <= ch2 || uw <= cw2 { - return shape; - } - vec![(uh - ch2, uw - cw2)] + let u = |v: &u32| *v as u64; + vec![conv_t_sides(h, w, u(cout), u(kh), u(kw), u(sh), u(sw), u(ph), u(pw), u(oph), u(opw))?] } (_, ADD) | (_, MUL) => { if !same(hw[op.ins[1] as usize]) { @@ -83,21 +125,9 @@ fn op_sizes(g: &Graph, op: &crate::graph::Op, hw: &[(u64, u64)], mode: Mode) -> } vec![(h, w)] } - (Params::Shuffle { r }, PIXEL_SHUFFLE) => { - let r = *r as u64; - vec![(capped(mul(h, r)?)?, capped(mul(w, r)?)?)] - } - (Params::Shuffle { r }, _) => { - let r = *r as u64; - if h % r != 0 || w % r != 0 { - return shape; - } - vec![(h / r, w / r)] - } - (Params::PadRep { m }, _) => { - let m = *m as u64; - vec![(capped(mul(h.div_ceil(m), m)?)?, capped(mul(w.div_ceil(m), m)?)?)] - } + (Params::Shuffle { r }, PIXEL_SHUFFLE) => vec![shuffle_sides(h, w, *r as u64)?], + (Params::Shuffle { r }, _) => vec![unshuffle_sides(h, w, *r as u64)?], + (Params::PadRep { m }, _) => vec![pad_rep_sides(h, w, *m as u64)?], (_, CROP_TO) => { let (rh, rw) = hw[op.ins[1] as usize]; if rh > h || rw > w { @@ -115,11 +145,7 @@ fn op_sizes(g: &Graph, op: &crate::graph::Op, hw: &[(u64, u64)], mode: Mode) -> Operand::Scalar(s) => sv[s as usize] as i128, } }; - let (s0, l) = (v(start), v(len)); - if s0 < 0 || l < 1 || s0 + l > n as i128 { - return Err(Fail::Shape); - } - Ok(l as u64) + crop_side(v(start), v(len), n) } Mode::Load => { // The output is planned on the largest length the scalar's range diff --git a/wai/wai-ops/src/proofs/arith.rs b/wai/wai-ops/src/proofs/arith.rs new file mode 100644 index 000000000..beb875da0 --- /dev/null +++ b/wai/wai-ops/src/proofs/arith.rs @@ -0,0 +1,371 @@ +//! The integer functions of §2 and the requantisation of §5.1: K1, K3, K13, K17 and +//! K32 (the 512-bit arithmetic of the bounds pass). + +use alloc::vec; + +use super::{Rec, any_round}; +use crate::graph::{BiasKind, Round, Rq}; +use crate::interp::{Observe, exp_observed, round, rq_apply}; +use crate::xint::I512; + +/// Whether `q = ⌊t / 2^s⌋` for `s ≤ 127`: `q·2^s` is formed with no bit lost, and +/// `0 ≤ t − q·2^s < 2^s`. +fn is_floor(q: i128, t: i128, s: u32) -> bool { + let qs = q << s; + if qs >> s != q { + return false; + } + match t.checked_sub(qs) { + Some(rem) => rem >= 0 && (rem as u128) < (1u128 << s), + None => false, + } +} + +/// K3. `R_floor`, `R_half_up` and `R_half_even` (§2) each equal their definition, for +/// every `p` in `i128` and every shift `s` in `0..=127` (the range `rq.shift`, +/// `chscale`'s `s`, `scale_index` and `block_stat` allow). The reference is the +/// defining inequality of the floor division, `q·2^s ≤ t < (q + 1)·2^s`, checked with +/// no value wrapping. `R_half_up` forms `p + 2^(s−1)`; it returns `None` exactly when +/// that value leaves `i128`, which a certified graph never forms (§8.3, `rq.p`). +#[kani::proof] +fn k03_rounding_is_its_definition() { + let p: i128 = kani::any(); + let s: u32 = kani::any(); + kani::assume(s <= 127); + let r = any_round(); + let got = round(p, s, r); + if s == 0 { + assert_eq!(got, Some(p), "a shift of 0 leaves p as it is"); + return; + } + let h = 1i128 << (s - 1); + match r { + Round::Floor => { + let q = got.expect("R_floor is formed for every p"); + assert!(is_floor(q, p, s), "R_floor(p, s) = ⌊p / 2^s⌋"); + } + Round::HalfUp => match p.checked_add(h) { + Some(t) => { + let q = got.expect("formed whenever p + 2^(s−1) fits i128"); + assert!(is_floor(q, t, s), "R_half_up(p, s) = ⌊(p + 2^(s−1)) / 2^s⌋"); + } + None => assert!(got.is_none(), "no result only when p + 2^(s−1) leaves i128"), + }, + Round::HalfEven => { + let q = got.expect("R_half_even is formed for every p"); + // q0 = ⌊p / 2^s⌋, r = p − q0·2^s, h = 2^(s−1): q0 + 1 if r > h, or r = h and + // q0 odd; else q0. + let q0 = p >> s; + assert!(is_floor(q0, p, s)); + let rem = (p - (q0 << s)) as u128; + let h = h as u128; + let want = if rem > h || (rem == h && q0 & 1 == 1) { q0 + 1 } else { q0 }; + assert_eq!(q, want, "R_half_even(p, s) as §2 defines it"); + } + } +} + +/// K3. Each rounding is non-decreasing in `p` (§2; §8.3's `rq.q` rule relies on it), +/// for every `p₁ ≤ p₂` in `i128` and every shift in `0..=127`. `R_half_up`'s `None` +/// (its addend leaves `i128`) is monotone too: it never follows a larger `p` that had a +/// result. +#[kani::proof] +fn k03_rounding_is_monotone() { + let a: i128 = kani::any(); + let b: i128 = kani::any(); + kani::assume(a <= b); + let s: u32 = kani::any(); + kani::assume(s <= 127); + let r = any_round(); + let (ra, rb) = (round(a, s, r), round(b, s, r)); + if let Some(qb) = rb { + let qa = ra.expect("a smaller p has a result whenever a larger one does"); + assert!(qa <= qb, "non-decreasing in p"); + } +} + +// ------------------------------------------------------------------------------- K1 + +/// K1. `rq` (§5.1), in every rounding mode and every bias placement, equals its +/// definition: `t = v + pre`, `p = t·m`, `q = R(p, s)`, `y = q + post`, each formed +/// exactly. Window: `v`, `m` and the bias are any `i64`, `m` may be absent, and `s` is +/// any shift in `0..=127`. +/// +/// The harness reads the values the implementation forms ([`Rec`]): `rq.t`, then +/// `rq.p` (and `p + 2^(s−1)` under `half_up` and `half_even`), `rq.q` and `rq.y`. It +/// shows that `t` is `v + pre`; that `q` is `R(p, s)` by the defining inequality; that +/// `y` is `q + post` with `q` at full width (the cover reaches a `q` outside `i64` with a +/// `y` inside it); that the result is `y`; and that the implementation refuses, and +/// never wraps, exactly where a value leaves `i128`: the product (Rust's checked +/// multiplication, exact or `None` by the language's definition), the addend, or the +/// bias. Nothing panics. +#[kani::proof] +fn k01_rq_is_its_definition() { + let v: i64 = kani::any(); + let mult: Option = if kani::any() { Some(kani::any()) } else { None }; + let s: u8 = kani::any(); + kani::assume(s <= 127); + let r = any_round(); + let b: i64 = kani::any(); + let bk: u8 = kani::any(); + kani::assume(bk < 3); + let bias_kind = [BiasKind::None, BiasKind::Pre, BiasKind::Post][bk as usize]; + let rq = Rq { + round: r, + bias_kind, + m_kind: if mult.is_some() { 1 } else { 0 }, + s_kind: 1, + m_bytes: if mult.is_some() { 8 } else { 0 }, + b_bytes: if bias_kind == BiasKind::None { 0 } else { 8 }, + mult: mult.into_iter().collect(), + shift: vec![s], + bias: if bias_kind == BiasKind::None { vec![] } else { vec![b] }, + }; + let mut rec = Rec::new(); + let got = rq_apply(&rq, 0, v as i128, 0, &mut rec); + let s = s as u32; + let pre = if bias_kind == BiasKind::Pre { b as i128 } else { 0 }; + let post = if bias_kind == BiasKind::Post { b as i128 } else { 0 }; + assert!(rec.n >= 1 && rec.v[0] == v as i128 + pre, "rq.t = v + pre, exactly"); + if rec.n == 1 { + assert!(mult.is_some() && got.is_none(), "only a product past i128 stops here, refused"); + return; + } + let p = rec.v[1]; + if mult.is_none() { + assert_eq!(p, rec.v[0], "with no multiplier, p = t"); + } + let half = r != Round::Floor && s >= 1; + let addend = if half { p.checked_add(1i128 << (s - 1)) } else { None }; + let k = if addend.is_some() { 3 } else { 2 }; + if let Some(a) = addend { + assert_eq!(rec.v[2], a, "rq.p's second value is p + 2^(s−1)"); + } + if rec.n == k { + assert!(got.is_none(), "no rq.q only when it is refused"); + assert!(half && addend.is_none() && r == Round::HalfUp, "only half_up's addend past i128 stops here"); + return; + } + let q = rec.v[k]; + match r { + _ if s == 0 => assert_eq!(q, p), + Round::Floor => assert!(is_floor(q, p, s), "R_floor"), + Round::HalfUp => assert!(is_floor(q, addend.expect("formed"), s), "R_half_up"), + Round::HalfEven => { + let q0 = p >> s; + assert!(is_floor(q0, p, s)); + let rem = (p - (q0 << s)) as u128; + let h = 1u128 << (s - 1); + assert_eq!(q, if rem > h || (rem == h && q0 & 1 == 1) { q0 + 1 } else { q0 }, "R_half_even"); + } + } + match q.checked_add(post) { + None => assert!(got.is_none() && rec.n == k + 1, "a y past i128 is refused, never wrapped"), + Some(y) => { + assert!(rec.n == k + 2 && rec.v[k + 1] == y, "rq.y = q + post"); + assert_eq!(got, Some(y)); + kani::cover!(i64::try_from(q).is_err() && i64::try_from(y).is_ok(), "q outside i64 with y inside it: q is held at full width"); + } + } +} + +// ------------------------------------------------------------------------------ K13 + +/// K13. `isqrt` (§2) as the interpreter forms it, the standard library's `u128::isqrt` +/// (`igdn`'s `r`, `rsqrt_q16`'s `r`), is `⌊√n⌋`: `r² ≤ n < (r + 1)²`. Window: every +/// `n` below 2^32, which reaches the `u32` stages through the `u128` and `u64` entry +/// points; the stages for wider values divide by symbolic values, and at 2^64 the +/// check had not closed in 20 minutes. +#[kani::proof] +fn k13_isqrt_u128_is_floor_sqrt() { + let n: u32 = kani::any(); + let n = n as u128; + let r = n.isqrt(); + assert!(r * r <= n, "r² ≤ n"); + assert!(n < (r + 1) * (r + 1), "n < (r + 1)²"); +} + +/// K13. `isqrt` (§2) as the bounds pass forms it, in 512 bits (`igdn.r`, `r0` of +/// `layernorm_c` and `l2norm`): `r² ≤ n < (r + 1)²`. The digit-by-digit loop runs +/// the same code at every width, one iteration per two bits. Window: every `n` below +/// 2^32 (the loop's 16 iterations; at 2^64 every 512-bit operation of its 32 +/// iterations had not finished symbolic execution in 21 minutes). +#[kani::proof] +#[kani::unwind(20)] +fn k13_isqrt_i512_is_floor_sqrt() { + let n: u32 = kani::any(); + let r = I512::from_u64(n as u64).isqrt().to_i128().expect("isqrt(n) < 2^16") as u128; + let n = n as u128; + assert!(r * r <= n, "r² ≤ n"); + assert!(n < (r + 1) * (r + 1), "n < (r + 1)²"); +} + +/// K13. `isqrt_ceil` (§2) in 512 bits (lemma L1's `isqrt_ceil(C)`) is the smallest `r` +/// with `r² ≥ n`. Window: every `n` below 2^32. +#[kani::proof] +#[kani::unwind(20)] +fn k13_isqrt_ceil_i512_is_ceil_sqrt() { + let n: u32 = kani::any(); + let c = I512::from_u64(n as u64).isqrt_ceil().to_i128().expect("isqrt_ceil(n) ≤ 2^16") as u128; + let n = n as u128; + assert!(c * c >= n, "isqrt_ceil(n)² ≥ n"); + assert!(c == 0 || (c - 1) * (c - 1) < n, "and it is the smallest such r"); +} + +// ------------------------------------------------------------------------------ K17 + +/// The values an observed run reports, in the order it reports them. +struct Seen { + v: [i128; 4], + n: usize, +} + +impl Observe for Seen { + fn see(&mut self, _op: u32, _key: &'static str, v: i128) { + if self.n < 4 { + self.v[self.n] = v; + } + self.n += 1; + } +} + +/// K17. `exp_neg_q16(x)` (§2) for every `x ∈ [−(2^63 − 1), 0]`: the result lies in +/// `[0, 65553]`, and the four values §2 names, as the interpreter forms them, lie in +/// the intervals §8.3's `exp_neg_q16` rule records — `exp.negx = −x`, +/// `exp.nl = 45426·⌊u/45426⌋` (so `0 ≤ u − exp.nl < 45426`), +/// `exp.t2 ∈ [43245², 88670²]` and `exp.c ∈ [0, 23495·⌊88670²/2^16⌋]` — each of which +/// fits `i64` (class `acc`), so nothing overflows a 64-bit implementation. At +/// `x = −2^63`, `exp.negx = 2^63` does not fit `i64`, so no certified graph forms it. +fn exp_ranges(x: i64) { + let mut seen = Seen { v: [0; 4], n: 0 }; + let e = exp_observed(x as i128, 0, &mut seen); + assert_eq!(seen.n, 4, "exp.negx, exp.nl, exp.t2 and exp.c, once each"); + let [u, nl, t2, c] = seen.v; + assert_eq!(u, -(x as i128), "exp.negx = −x"); + assert!(u <= i64::MAX as i128, "exp.negx fits i64"); + assert!(0 <= nl && nl <= u && u - nl < 45426, "exp.nl = 45426·⌊u/45426⌋"); + assert!(43245 * 43245 <= t2 && t2 <= 88670 * 88670, "exp.t2 ∈ [43245², 88670²]"); + assert!(0 <= c && c <= 23495 * ((88670 * 88670) >> 16), "exp.c ∈ [0, 23495·⌊88670²/2^16⌋]"); + assert!((0..=65553).contains(&e), "the result lies in [0, 65553]"); + kani::cover!(x == 0 && e == 65553, "exp_neg_q16(0) = 65553"); +} + +/// K17 on its window: every `x ∈ [−(2^63 − 1), 0]`. +#[cfg(kani_open)] +#[kani::proof] +fn k17_exp_neg_q16_ranges() { + let x: i64 = kani::any(); + kani::assume(x <= 0 && x > i64::MIN); + exp_ranges(x); +} + +/// K17 on `x ∈ [−(2^31 − 1), 0]`: the same statement. Past `x ≤ −45426·63` the +/// result is 0 whatever `x`, and every intermediate depends on `x` only through +/// `n = ⌊−x/45426⌋` and the remainder, which this window takes through every value. +#[kani::proof] +fn k17_exp_neg_q16_ranges_i32() { + let x: i32 = kani::any(); + kani::assume(x <= 0 && x > i32::MIN); + exp_ranges(x as i64); +} + +// ------------------------------------------------------------------------------ K32 + +const CAP: u32 = 255; + +/// An operand at a saturation edge of §8.1: `±(2^255 − d)` for `d < 2^16`, or a small +/// value `w`. +#[derive(Clone, Copy)] +enum Edge { + Near { neg: bool, d: u16 }, + Small(i64), +} + +fn any_edge() -> Edge { + if kani::any() { Edge::Near { neg: kani::any(), d: kani::any() } } else { Edge::Small(kani::any()) } +} + +fn value(e: Edge) -> I512 { + match e { + Edge::Near { neg, d } => { + let v = I512::pow2(CAP).sub(I512::from_u64(d as u64)); + if neg { v.neg() } else { v } + } + Edge::Small(w) => I512::from_i64(w), + } +} + +/// The product of two edge operands, built from shifts and additions of small values: +/// `(2^255 − d₁)(2^255 − d₂) = 2^510 − (d₁ + d₂)·2^255 + d₁·d₂`, and +/// `(2^255 − d)·w = w·2^255 − w·d`. +fn product(a: Edge, b: Edge) -> I512 { + match (a, b) { + (Edge::Near { neg: n1, d: d1 }, Edge::Near { neg: n2, d: d2 }) => { + let (d1, d2) = (d1 as u64, d2 as u64); + let m = I512::pow2(2 * CAP).sub(I512::from_u64(d1 + d2).shl(CAP)).add(I512::from_u64(d1 * d2)); + if n1 != n2 { m.neg() } else { m } + } + (Edge::Near { neg, d }, Edge::Small(w)) | (Edge::Small(w), Edge::Near { neg, d }) => { + let m = I512::from_i64(w).shl(CAP).sub(I512::from_i128(w as i128 * d as i128)); + if neg { m.neg() } else { m } + } + (Edge::Small(x), Edge::Small(y)) => I512::from_i128(x as i128 * y as i128), + } +} + +fn le(a: I512, b: I512) -> bool { + a.cmp(&b) != core::cmp::Ordering::Greater +} + +/// K32. The bounds pass's 512-bit arithmetic does not wrap on saturated operands +/// (§8.1, *Width*): for operands at the saturation edges, `add`, `sub`, `neg` and `abs` +/// give the exact values. Window: `d` below 2^16, and the small operand any `i64`. +#[kani::proof] +#[kani::unwind(10)] +fn k32_xint_add_sub_neg_exact_at_the_saturation_edges() { + let (ea, eb) = (any_edge(), any_edge()); + let (a, b) = (value(ea), value(eb)); + let c = I512::pow2(CAP); + // Every edge operand lies in [−2^255, 2^255], which `sat` leaves unchanged. + assert!(!a.sat().1 && !b.sat().1); + // add, sub, neg and abs: exact, so they invert, and the signs are those of the + // exact values (a wrap would flip one). + let s = a.add(b); + assert!(le(s.abs(), I512::pow2(CAP + 1)), "|a + b| ≤ 2^256"); + assert!(s.sub(b) == a && s.sub(a) == b); + assert!(a.is_neg() || b.is_neg() || !s.is_neg(), "a sum of non-negatives is non-negative"); + assert!(!a.is_neg() || !b.is_neg() || s.is_neg(), "a sum of negatives is negative"); + assert!(a.neg().neg() == a); + assert!(le(a.abs(), c) && !a.abs().is_neg(), "|a| ≤ 2^255"); +} + +/// K32. The bounds pass's 512-bit product does not wrap on saturated operands: at the +/// saturation edges, `mul` gives `(2^255 − d₁)(2^255 − d₂) = 2^510 − (d₁ + d₂)·2^255 + +/// d₁·d₂` with the sign of the operands, and `±(2^255 − d)·w = ±(w·2^255 − w·d)`, and +/// `|a·b| ≤ 2^510`. Window: `d`, `d₁`, `d₂` below 2^16, `w` any `i64`. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(10)] +fn k32_xint_mul_exact_at_the_saturation_edges() { + let (ea, eb) = (any_edge(), any_edge()); + let p = value(ea).mul(value(eb)); + assert!(p == product(ea, eb), "the product is exact"); + assert!(le(p.abs(), I512::pow2(2 * CAP)), "|a·b| ≤ 2^510"); +} + +/// K32. `sat` (§8.1) clamps to `[−2^255, 2^255]`, reports exactly when it changed a +/// value, and is non-decreasing. Window: every pair of 512-bit values. +#[kani::proof] +#[kani::unwind(10)] +fn k32_sat_is_a_monotone_clamp() { + let a = I512::from_limbs(kani::any()); + let b = I512::from_limbs(kani::any()); + let c = I512::pow2(CAP); + let (sa, ha) = a.sat(); + assert!(sa.cmp(&c) != core::cmp::Ordering::Greater && sa.cmp(&c.neg()) != core::cmp::Ordering::Less); + assert!(ha == (sa != a), "the flag is set exactly when the value changed"); + assert!(!ha || a.cmp(&c) == core::cmp::Ordering::Greater || a.cmp(&c.neg()) == core::cmp::Ordering::Less); + if a.cmp(&b) != core::cmp::Ordering::Greater { + assert!(sa.cmp(&b.sat().0) != core::cmp::Ordering::Greater, "sat is non-decreasing"); + } +} diff --git a/wai/wai-ops/src/proofs/conv_t.rs b/wai/wai-ops/src/proofs/conv_t.rs new file mode 100644 index 000000000..7d5ff2fa7 --- /dev/null +++ b/wai/wai-ops/src/proofs/conv_t.rs @@ -0,0 +1,138 @@ +//! `conv_transpose` (§5.3): the interpreter's scatter form against the text's gather +//! form (K7) and the phase form of §9.3 (K8). +//! +//! Each harness runs the kernel at a set of concrete shapes, one call site per shape, +//! so the checker unrolls every loop exactly; weights, inputs, the bias, the rounding +//! and the shift are symbolic. The shapes span the window — kernels up to 3×3, strides +//! up to 3, padding up to 2, output padding up to 3, planes up to 3×3, one channel each +//! way — and include a stride larger than the kernel, where some positions no tap +//! reaches, and a non-square kernel and stride. + +use alloc::vec; +use alloc::vec::Vec; + +use super::any_round; +use crate::graph::{BiasKind, Rq}; +use crate::interp::{self, Quiet, Tensor, round}; + +/// The kernel's output, and the operands, at one shape. +struct Run { + out: Tensor, + w: Vec, + x: Vec, + rq: Rq, +} + +#[allow(clippy::too_many_arguments)] +fn run(kh: usize, kw: usize, sh: usize, sw: usize, ph: usize, pw: usize, oph: usize, opw: usize, hh: usize, ww: usize) -> Run { + let wraw: [i8; 9] = kani::any(); + let w: Vec = wraw[..kh * kw].iter().map(|&v| v as i64).collect(); + let xraw: [i8; 9] = kani::any(); + let x: Vec = xraw[..hh * ww].iter().map(|&v| v as i64).collect(); + let b: i8 = kani::any(); + let s: u8 = kani::any(); + kani::assume(s <= 4); + let rq = Rq { round: any_round(), bias_kind: BiasKind::Pre, m_kind: 0, s_kind: 1, m_bytes: 0, b_bytes: 4, mult: vec![], shift: vec![s], bias: vec![b as i64] }; + let (oh, ow) = ((hh - 1) * sh + kh + oph - 2 * ph, (ww - 1) * sw + kw + opw - 2 * pw); + let out = interp::k_conv_t(&Tensor::new(1, hh as u32, ww as u32, x.clone()), 1, kh, kw, sh, sw, ph, pw, oph, opw, &rq, &w, oh, ow, 0, &mut Quiet).expect("i8 operands"); + Run { out, w, x, rq } +} + +/// `rq_0` of an accumulator, as §5.1 writes it for this block (no multiplier). +fn rq0(rq: &Rq, acc: i128) -> i128 { + round(acc + rq.bias[0] as i128, rq.shift[0] as u32, rq.round).expect("small values") +} + +/// §5.3's gather form at a symbolic output position (so at every one), against the +/// kernel. +#[allow(clippy::too_many_arguments)] +fn gather(kh: usize, kw: usize, sh: usize, sw: usize, ph: usize, pw: usize, oph: usize, opw: usize, hh: usize, ww: usize) { + let r = run(kh, kw, sh, sw, ph, pw, oph, opw, hh, ww); + let (oh, ow) = (r.out.h as usize, r.out.w as usize); + let (y, xo): (usize, usize) = (kani::any(), kani::any()); + kani::assume(y < oh && xo < ow); + { + { + let mut acc: i128 = 0; + for i in 0..kh { + for j in 0..kw { + let (ty, tx) = ((y + ph) as i64 - i as i64, (xo + pw) as i64 - j as i64); + if ty < 0 || tx < 0 || ty % sh as i64 != 0 || tx % sw as i64 != 0 { + continue; + } + let (u, v) = ((ty / sh as i64) as usize, (tx / sw as i64) as usize); + if u >= hh || v >= ww { + continue; + } + acc += r.w[i * kw + j] as i128 * r.x[u * ww + v] as i128; + } + } + assert_eq!(r.out.data[y * ow + xo] as i128, rq0(&r.rq, acc), "gather = scatter, then crop"); + } + } +} + +/// §9.3's phase form at a symbolic output position (so at every one), against the +/// kernel. +#[allow(clippy::too_many_arguments)] +fn phase(kh: usize, kw: usize, sh: usize, sw: usize, ph: usize, pw: usize, oph: usize, opw: usize, hh: usize, ww: usize) { + let r = run(kh, kw, sh, sw, ph, pw, oph, opw, hh, ww); + let (oh, ow) = (r.out.h as usize, r.out.w as usize); + let (y, xo): (usize, usize) = (kani::any(), kani::any()); + kani::assume(y < oh && xo < ow); + { + { + let (ry, rx) = ((y + ph) % sh, (xo + pw) % sw); + let (u, v) = (((y + ph) / sh) as i64, ((xo + pw) / sw) as i64); + let mut z: i128 = 0; + let mut t = 0; + while ry + sh * t < kh { + let mut t2 = 0; + while rx + sw * t2 < kw { + let (iy, ix) = (u - t as i64, v - t2 as i64); + if iy >= 0 && ix >= 0 && iy < hh as i64 && ix < ww as i64 { + z += r.w[(ry + sh * t) * kw + rx + sw * t2] as i128 * r.x[iy as usize * ww + ix as usize] as i128; + } + t2 += 1; + } + t += 1; + } + assert_eq!(r.out.data[y * ow + xo] as i128, rq0(&r.rq, z), "the phase form is the transposed convolution"); + } + } +} + +/// K7. The interpreter's `conv_transpose` (scatter into an uncropped plane, then crop) +/// equals §5.3's gather form at every output position — the sum over `i < kh, j < kw` +/// with `ty = y + ph − i ≥ 0`, `ty mod sh = 0`, `ty / sh < H`, and likewise for `x`, of +/// `Wt[i][j]·X[ty / sh][tx / sw]`, then `rq` — and a position no tap reaches holds +/// `rq(0)`. Window: the shapes below, with every weight, input, bias, rounding and shift +/// up to 4 symbolic. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(12)] +fn k07_conv_transpose_gather_equals_scatter() { + match kani::any::() % 4 { + 0 => gather(3, 3, 2, 2, 1, 1, 1, 1, 2, 2), + 1 => gather(3, 3, 3, 3, 2, 2, 3, 3, 2, 2), + 2 => gather(2, 2, 3, 3, 0, 0, 0, 0, 2, 2), + _ => gather(3, 1, 2, 1, 1, 0, 1, 0, 2, 3), + } +} + +/// K8. The phase form of §9.3 equals the transposed convolution: for +/// `ρ = ((y + ph) mod sh, (x + pw) mod sw)` and `(u, v) = (⌊(y + ph)/sh⌋, ⌊(x + pw)/sw⌋)`, +/// `Z_ρ[u][v] = Σ_{t, t′} Wt[ρy + sh·t][ρx + sw·t′]·X̃[u − t][v − t′]` over the phase's +/// sub-kernel, with `X̃` zero outside the input, and the output is `rq(Z_ρ[u][v])`. +/// Window: K7's shapes. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(12)] +fn k08_conv_transpose_phase_form() { + match kani::any::() % 4 { + 0 => phase(3, 3, 2, 2, 1, 1, 1, 1, 2, 2), + 1 => phase(3, 3, 3, 3, 2, 2, 3, 3, 2, 2), + 2 => phase(2, 2, 3, 3, 0, 0, 0, 0, 2, 2), + _ => phase(3, 1, 2, 1, 1, 0, 1, 0, 2, 3), + } +} diff --git a/wai/wai-ops/src/proofs/igdn.rs b/wai/wai-ops/src/proofs/igdn.rs new file mode 100644 index 000000000..e37090779 --- /dev/null +++ b/wai/wai-ops/src/proofs/igdn.rs @@ -0,0 +1,44 @@ +//! `igdn` (§5.7) against the scalar reference every `WHM1` and `WAM1` decoder uses +//! today, and its fast paths (K10). Only the host compiles this: the reference and the +//! fast kernels are `wai-rs` sources it includes beside this crate's. + +use alloc::vec::Vec; + +use crate::interp::{self, Quiet, Tensor}; + +/// K10. `igdn` as the operator set defines it (the interpreter: each term floored, then +/// summed; `isqrt` of the clamped norm; the product shifted) equals +/// `int_transform::reference::igdn`, and the fast kernel's narrow paths (32-bit terms, +/// 64-bit sums and products) equal both. Window: `C ≤ 2`, two positions, `x` and `γ` +/// in `i8`, `β` in `i16`, `gf` and `frac` up to 16; on it every narrowing condition +/// holds, so the narrowest path runs. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(6)] +fn k10_igdn_equals_the_reference() { + igdn_equal(if kani::any() { 1 } else { 2 }, 2); +} + +/// K10 at one channel and one position: the same statement on a narrower window. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(6)] +fn k10_igdn_equals_the_reference_c1() { + igdn_equal(1, 1); +} + +fn igdn_equal(c: usize, hw: usize) { + let xraw: [i8; 4] = kani::any(); + let graw: [i8; 4] = kani::any(); + let braw: [i16; 2] = kani::any(); + let (gf, frac): (u32, u32) = (kani::any(), kani::any()); + kani::assume(gf <= 16 && frac <= 16); + let x: Vec = xraw[..c * hw].iter().map(|&v| v as i64).collect(); + let gamma: Vec = graw[..c * c].iter().map(|&v| v as i64).collect(); + let beta: Vec = braw[..c].iter().map(|&v| v as i64).collect(); + let reference = crate::int_transform::reference::igdn(&x, c, hw, frac, &gamma, &beta, gf); + let ops = interp::k_igdn(&Tensor::new(c as u32, 1, hw as u32, x.clone()), gf, frac, &gamma, &beta, 0, &mut Quiet).expect("igdn on i8 inputs is formed"); + assert_eq!(ops.data, reference, "the operator set's igdn is the reference"); + let fast = crate::int_kernels::igdn(&x, c, hw, frac, &gamma, &beta, gf).expect("the fast path applies"); + assert_eq!(fast, reference, "the narrow fast path is the reference"); +} diff --git a/wai/wai-ops/src/proofs/limb.rs b/wai/wai-ops/src/proofs/limb.rs new file mode 100644 index 000000000..62e8098e3 --- /dev/null +++ b/wai/wai-ops/src/proofs/limb.rs @@ -0,0 +1,155 @@ +//! A 32-bit fabric's arithmetic under `acc32` (§6, §7.3): K2 and K2b on the model in +//! [`crate::limb32`], and K5 and K6 on the chunked sums `K_c` allows. + +use super::any_round; +use crate::graph::Round; +use crate::interp::round; +use crate::limb32::{self, W64}; + +// ------------------------------------------------------------------------------- K2 + +/// K2. The 16-bit-limb product: for every value of the four partial products a +/// 16 × 16-bit multiplication can give (each in `[0, (2^16 − 1)²]`, taken independently, +/// which includes every combination real halves produce), the 32-bit adds with their +/// carries give `p00 + (p01 + p10)·2^16 + p11·2^32` exactly, as two words. Kani's +/// overflow checks show the partial products themselves never wrap a `u32`. +/// +/// With `a = a1·2^16 + a0` and `b = b1·2^16 + b0`, the integer identity +/// `a·b = a0·b0 + (a0·b1 + a1·b0)·2^16 + a1·b1·2^32` then makes the result the `u64` +/// product for every `u32 × u32`. The harnesses below show that the partial products +/// do not wrap and that the magnitudes and the negation are exact; `mul_i32` is those +/// steps in sequence, so the limb product is the `i64` product for every `i32 × i32`. +/// The identity is arithmetic, not re-derived by a second multiplier circuit, for the +/// reason the module documentation gives; the unit tests of `limb32` compare the whole +/// product with `i64` multiplication at the edges and on samples. +#[kani::proof] +fn k02_limb_combination_is_exact() { + let p: [u32; 4] = kani::any(); + let max = 0xFFFF * 0xFFFF; + kani::assume(p.iter().all(|&v| v <= max)); + let got = limb32::combine(p); + let want = p[0] as u128 + ((p[1] as u128 + p[2] as u128) << 16) + ((p[3] as u128) << 32); + assert!(want < 1 << 64); + assert_eq!(((got.hi as u128) << 32) | got.lo as u128, want, "the carries are exact"); +} + +/// K2. The partial products are formed without wrapping: `partials` multiplies the +/// 16-bit halves in `u32` with Rust's unchecked operator, and Kani's overflow check on +/// each multiplication proves that none overflows, for every `a` and `b`. The halves +/// recompose the operands. +#[kani::proof] +fn k02_limb_partials_do_not_wrap() { + let (a, b): (u32, u32) = (kani::any(), kani::any()); + let _ = limb32::partials(a, b); + let (a0, a1, b0, b1) = (a & 0xFFFF, a >> 16, b & 0xFFFF, b >> 16); + assert_eq!((a1 << 16) | a0, a); + assert_eq!((b1 << 16) | b0, b); +} + +/// K2. The signs: `|a|` is the magnitude for every `i32` (`2^31` for `−2^31`), the +/// two-word negation is negation modulo 2^64 for every 64-bit value, and the product +/// takes the negation exactly when one operand is negative. +#[kani::proof] +fn k02_limb_signs() { + let a: i32 = kani::any(); + assert_eq!(limb32::magnitude(a) as i64, (a as i64).abs(), "|a|"); + let v: i64 = kani::any(); + assert_eq!(limb32::neg(W64::from_i64(v)).to_i64(), v.wrapping_neg(), "−v, modulo 2^64"); + assert_eq!(W64::from_i64(v).to_i64(), v); +} + +// ------------------------------------------------------------------------------ K2b + +/// K2b. The epilogue on two words (§7.3): for every product `acc32` allows — any `p` +/// in `i64` whose `rq.p` interval, with `half_up`'s addend `2^(s−1)`, fits `i64` — every +/// shift `s ≤ 63` and every rounding, the two-word rounding shift, written with 32-bit +/// shifts that take their amount mod 32, equals `R_floor`, `R_half_up` and +/// `R_half_even` (§2, through [`round`], which K3 proves equal to them). Then the +/// `post` bias is added and the value narrowed to `i32`: exact whenever `rq.y` fits +/// `i32` (and so whenever `rq.q` and `rq.y` both do). +#[kani::proof] +fn k02b_limb_epilogue() { + let p: i64 = kani::any(); + let s: u32 = kani::any(); + kani::assume(s <= 63); + let r = any_round(); + kani::assume(r != Round::HalfUp || s == 0 || p as i128 + (1i128 << (s - 1)) <= i64::MAX as i128); + let q = round(p as i128, s, r).expect("formed for every product acc32 allows"); + let got = limb32::round(W64::from_i64(p), s, r); + assert_eq!(got.to_i64() as i128, q, "the two-word rounding shift is R(p, s)"); + let post: i32 = kani::any(); + let y = q + post as i128; + if i32::try_from(y).is_ok() { + assert_eq!(limb32::epilogue(W64::from_i64(p), s, r, post) as i128, y, "exact whenever rq.y fits i32"); + } +} + +// ------------------------------------------------------------------------- K5 and K6 + +/// A term interval and its `P = max(|lo|, |hi|)`, `1 ≤ P ≤ 2^31 − 1` (with `P ≥ 2^31`, +/// `K_c` is 0 and a fabric forms no 32-bit partial sum), with +/// `K_c = ⌊(2^31 − 1) / P⌋` (§6), which the certificate records as `k_c` (the +/// independent certifier recomputes every certificate's `k_c`). +fn term_interval() -> (i64, i64, usize) { + let (lo, hi): (i32, i32) = (kani::any(), kani::any()); + kani::assume(lo <= hi && lo > i32::MIN); + let p = (lo as i64).abs().max((hi as i64).abs()); + kani::assume(p >= 1); + (lo as i64, hi as i64, ((i32::MAX as i64) / p) as usize) +} + +/// K5. Chunked 32-bit partial sums (§6): for any `n ≤ 8` terms in a term interval, and +/// any partition of them into consecutive chunks of at most `K_c` terms, each chunk's +/// running sum fits `i32` at every step, and the chunk sums, widened and added, equal +/// the exact sum. Window: every term interval within `i32`, every partition. +#[kani::proof] +#[kani::unwind(10)] +fn k05_chunked_i32_sums() { + let (lo, hi, kc) = term_interval(); + let n: usize = kani::any(); + kani::assume(n <= 8); + let t: [i32; 8] = kani::any(); + kani::assume(t[..n].iter().all(|&v| lo <= v as i64 && v as i64 <= hi)); + // A partition: a cut after term i where cut[i] is set; no chunk longer than K_c. + let cut: [bool; 8] = kani::any(); + let (mut total, mut chunk, mut len, mut exact) = (0i64, 0i32, 0usize, 0i64); + for i in 0..n { + len += 1; + kani::assume(len <= kc); + chunk = chunk.checked_add(t[i]).expect("a chunk of at most K_c terms fits i32"); + exact += t[i] as i64; + if cut[i] || i + 1 == n { + total += chunk as i64; + chunk = 0; + len = 0; + } + } + assert_eq!(total, exact, "the chunked sum is the exact sum"); +} + +/// K6. An `n`-product dot instruction into one 32-bit lane (§6), for `n = 2` and `4`: +/// after `j` instructions the lane holds `n·j` products, and while `n·j ≤ K_c` it never +/// wraps, at every instruction and inside it. Window: every term interval within `i32`, +/// up to 8 products. +#[kani::proof] +#[kani::unwind(10)] +fn k06_dot_lane_never_wraps() { + let (lo, hi, kc) = term_interval(); + let n: usize = if kani::any() { 2 } else { 4 }; + let j: usize = kani::any(); + kani::assume((1..=4).contains(&j)); + kani::assume(n * j <= 8 && n * j <= kc); + let t: [i32; 8] = kani::any(); + kani::assume(t[..n * j].iter().all(|&v| lo <= v as i64 && v as i64 <= hi)); + let mut lane = 0i32; + let mut exact = 0i64; + for ins in 0..j { + let mut dot = 0i32; + for k in 0..n { + dot = dot.checked_add(t[ins * n + k]).expect("inside the instruction"); + exact += t[ins * n + k] as i64; + } + lane = lane.checked_add(dot).expect("the lane does not wrap"); + } + assert_eq!(lane as i64, exact); +} diff --git a/wai/wai-ops/src/proofs/mod.rs b/wai/wai-ops/src/proofs/mod.rs new file mode 100644 index 000000000..7669f4c9f --- /dev/null +++ b/wai/wai-ops/src/proofs/mod.rs @@ -0,0 +1,103 @@ +//! The model checker's harnesses for `wai-ops/1`: K1–K33 of the operator set's test +//! plan, each named `kNN_…` after its row. +//! +//! They are compiled only under `cfg(kani)`, and `wai-verify` hosts them: it includes +//! this crate's modules at its own root by `#[path]`, so `crate::` resolves the same +//! way there. Each harness states its window (the sizes and widths it is bounded to) +//! in its documentation. Bounded is not universal, and a harness claims only what it +//! checks. +//! +//! References are written independently of the code they check: a definition from +//! the text is checked as its defining inequalities, or recomputed in 512-bit +//! arithmetic ([`crate::xint::I512`]), never by calling the function under test. One +//! exception is stated where it applies: where both sides would multiply the same two +//! symbolic operands, the product is formed once and shared, because a SAT-based +//! checker does not decide the equivalence of two multiplier circuits in bounded time. +//! Rust's checked multiplication is exact by the language's definition, which the +//! checker models bit for bit. + +// Harnesses gated by `cfg(kani_open)` state a property of the test plan at a window +// on which the model checker did not finish within the budget its CI shard allows +// (each says which, and the pull request that added them records how long it ran). +// They are compiled and run only on request: +// +// RUSTFLAGS="--cfg kani_open" cargo kani --lib --exact --harness +// +// The helpers and imports only they use are then unused in an ordinary run. +#![allow(dead_code, unused_imports)] + +use crate::graph::Round; +use crate::interp::Observe; + +mod arith; +mod conv_t; +mod igdn; +mod limb; +mod plan; +mod rules; +mod sound; +mod stage; + +/// A symbolic rounding mode. +pub(crate) fn any_round() -> Round { + let k: u8 = kani::any(); + kani::assume(k < 3); + match k { + 0 => Round::Floor, + 1 => Round::HalfUp, + _ => Round::HalfEven, + } +} + +/// The values an observed run reports (§8.5's intermediates), by position: an +/// operator reports them in a fixed order, which each harness states. Only the first +/// `40` are kept. +pub(crate) struct Rec { + pub v: [i128; 40], + pub n: usize, +} + +impl Rec { + pub fn new() -> Rec { + Rec { v: [0; 40], n: 0 } + } +} + +impl Observe for Rec { + fn see(&mut self, _op: u32, _key: &'static str, v: i128) { + if self.n < 40 { + self.v[self.n] = v; + } + self.n += 1; + } +} + +/// An observer that holds every value an operator forms to the interval given for its +/// key (§8.5, Table 8.5-A), and counts what it sees. A key not listed fails. +pub(crate) struct Keyed { + pub rules: [(&'static str, rules::R); N], + pub seen: u32, +} + +/// A key's tag: its length, its last byte and its second byte. The keys one operator +/// reports differ in their tags (`conv.term`, `conv.acc`, `rq.t`, `rq.p`, …), and a tag +/// is three loads, where comparing strings is a loop the checker unrolls at every call. +fn tag(k: &str) -> (usize, u8, u8) { + let b = k.as_bytes(); + (b.len(), b[b.len() - 1], b[1]) +} + +impl Observe for Keyed { + fn see(&mut self, _op: u32, key: &'static str, v: i128) { + self.seen += 1; + let t = tag(key); + let mut found = false; + for (k, r) in self.rules.iter() { + if tag(k) == t { + assert!(rules::within(*r, v), "a value lies in its key's interval"); + found = true; + } + } + assert!(found, "every key the operator reports has an interval"); + } +} diff --git a/wai/wai-ops/src/proofs/plan.rs b/wai/wai-ops/src/proofs/plan.rs new file mode 100644 index 000000000..c28d3dbcb --- /dev/null +++ b/wai/wai-ops/src/proofs/plan.rs @@ -0,0 +1,373 @@ +//! The plans, the graph form and the data-movement operators: K12 (the lowerings' +//! predicates and their search), K15 (`lut16`'s index), K16 (movement), K31 (`WHG1` +//! parse) and K33 (the run-time plan). + +use alloc::vec; +use alloc::vec::Vec; + +use crate::bounds::{self, Iv}; +use crate::graph::{BiasKind, Graph, Op, Params, Round, Rq, TensorRec, opcode::*}; +use crate::interp::{self, Tensor}; +use crate::plan; +use crate::lower::{largest, p_conv, p_igdn, p_leaky}; +use crate::xint::I512; + +/// A symbolic `u32` in `[lo, hi]`. +fn range(lo: u32, hi: u32) -> u32 { + let v: u32 = kani::any(); + kani::assume(lo <= v && v <= hi); + v +} + +/// `n` symbolic `i8` values, as `i64`. +fn data(n: usize) -> Vec { + let raw: [i8; 72] = kani::any(); + raw[..n].iter().map(|&v| v as i64).collect() +} + +/// `0, 1, …, n − 1`: every element names its own position. +fn ids(n: usize) -> Vec { + (0..n as i64).collect() +} + +/// Every element of `out` is an input position, and no two are the same: with as many +/// elements as the input, a bijection. +fn is_permutation_of_ids(out: &[i64], n: usize) { + assert_eq!(out.len(), n); + let (k1, k2): (usize, usize) = (kani::any(), kani::any()); + kani::assume(k1 < n && k2 < n && k1 != k2); + assert!(0 <= out[k1] && (out[k1] as usize) < n); + assert!(out[k1] != out[k2], "no input element is used twice"); +} + +// ------------------------------------------------------------------------------ K12 + +/// K12. The search of §13.2 returns the maximum: for a predicate that holds at `X` +/// whenever it holds at a larger value, `largest` gives the largest `X ∈ [0, 2^63]` at +/// which it holds, or `None` when it fails at 0. A predicate on `[0, 2^63]` that holds +/// below wherever it holds is `X ≤ T` for some `T`, or nowhere; the harness covers +/// every `T`. +#[kani::proof] +#[kani::unwind(66)] +fn k12_largest_returns_the_maximum() { + let t: u128 = kani::any(); + let nowhere: bool = kani::any(); + let got = largest(|x| !nowhere && x <= t); + if nowhere { + assert_eq!(got, None); + } else { + assert_eq!(got, Some(t.min(1 << 63))); + } +} + +/// K12. `P_ℓ` of a convolution layer (tags 0 and 1, §13.2) holds at `X` whenever it +/// holds at a larger `X`. Window: the term count, `Wm`, `Mm` and `Bm` in `u8`, any +/// shift in `0..=127`, and every `X′ ≤ X` in `u32`. +#[kani::proof] +#[kani::unwind(10)] +fn k12_p_conv_is_monotone() { + let (terms, wm, mm, bm): (u8, u8, u8, u8) = (kani::any(), kani::any(), kani::any(), kani::any()); + let s: u32 = range(0, 127); + let (a, b): (u32, u32) = (kani::any(), kani::any()); + kani::assume(a <= b); + let u = |v: u8| I512::from_u64(v as u64); + if p_conv(u(terms), u(wm), u(mm), u(bm), s, b as u128) { + assert!(p_conv(u(terms), u(wm), u(mm), u(bm), s, a as u128), "P holds below wherever it holds"); + } +} + +/// K12. `P_ℓ` of an `igdn` layer (tag 2, §13.2) holds at `X` whenever it holds at a +/// larger `X`. Window: `G` and `Bb` in `u8`, `c ≤ 4`, `gf` and `afrac` up to 16, and +/// every `X′ ≤ X` in `u8`. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(16)] +fn k12_p_igdn_is_monotone() { + let (g, bb): (u8, u8) = (kani::any(), kani::any()); + let c = range(1, 4); + let (gf, af) = (range(0, 16), range(1, 16)); + let (a, b): (u8, u8) = (kani::any(), kani::any()); + kani::assume(a <= b); + let u = |v: u64| I512::from_u64(v); + if p_igdn(u(g as u64), u(bb as u64), u(c as u64), gf, af, b as u128) { + assert!(p_igdn(u(g as u64), u(bb as u64), u(c as u64), gf, af, a as u128), "P holds below wherever it holds"); + } +} + +/// K12. `P_ℓ` of a `leaky` layer (tag 4, §13.2) holds at `X` whenever it holds at a +/// larger `X`. Window: `|slope_q|` in `u16`, every `X′ ≤ X` in `u32`. +#[kani::proof] +#[kani::unwind(10)] +fn k12_p_leaky_is_monotone() { + let q: u16 = kani::any(); + let (a, b): (u32, u32) = (kani::any(), kani::any()); + kani::assume(a <= b); + let s = I512::from_u64(q as u64); + if p_leaky(s, b as u128) { + assert!(p_leaky(s, a as u128), "P holds below wherever it holds"); + } +} + +// ------------------------------------------------------------------------------ K15 + +/// K15. `lut16` (§5.6): for every input range within `[−32767, 32767]` — which load +/// step 8 requires — and every value in it, the index `v + 32768` addresses the table; +/// and the rule refuses, at load, a range that passes either end. Window: every such +/// range and value; the table's entries do not affect the index. +#[kani::proof] +#[kani::unwind(10)] +fn k15_lut16_index_is_total() { + let (l, h): (i64, i64) = (kani::any(), kani::any()); + kani::assume(-32767 <= l && l <= h && h <= 32767); + let v: i64 = kani::any(); + kani::assume(l <= v && v <= h); + let t = vec![0i16; 65536]; + assert!(interp::k_lut16(&Tensor::new(1, 1, 1, vec![v]), &t, 0).is_ok(), "the index addresses the table"); + // One past either end: the rule's range check refuses the graph at load. + for (lo, hi) in [(-32768i64, 0i64), (0, 32768)] { + let op = Op { code: LUT16, ins: vec![0], outs: vec![1], p: Params::Lut16 { e_in: -128, e_out: -128, t: vec![0i16; 65536] } }; + let g = Graph { max_elems: 1 << 26, scalars: vec![], inputs: vec![], outputs: vec![1], tensors: vec![TensorRec::check(1, lo, hi), TensorRec::derived(1)], ops: vec![] }; + assert!(bounds::eval(&g, &op, &[Iv::of_i64(lo, hi)], None).lut_range, "a range past [−32767, 32767] is refused at load"); + } +} + +// ------------------------------------------------------------------------------ K16 + +/// `pixel_shuffle` at one shape: a bijection, and the element the text names. +fn shuffle_case(r: usize, co: usize, h: usize, w: usize) { + let c = co * r * r; + let n = c * h * w; + let (oh, ow) = plan::shuffle_sides(h as u64, w as u64, r as u64).expect("small sides"); + let out = interp::k_pixel_shuffle(&Tensor::new(c as u32, h as u32, w as u32, ids(n)), r, oh as usize, ow as usize); + is_permutation_of_ids(&out.data, n); + let (cc, y, x, i, j) = (range(0, co as u32 - 1) as usize, range(0, h as u32 - 1) as usize, range(0, w as u32 - 1) as usize, range(0, r as u32 - 1) as usize, range(0, r as u32 - 1) as usize); + let (oh, ow) = (h * r, w * r); + assert_eq!(out.data[(cc * oh + y * r + i) * ow + x * r + j], (((cc * r * r + i * r + j) * h + y) * w + x) as i64); +} + +/// K16. `pixel_shuffle` (§5.10) is a bijection, and `out[c][h·r + i][w·r + j]` is +/// `in[c·r² + i·r + j][h][w]`. Window: the shapes below, every output plane up to 4×4. +#[kani::proof] +#[kani::unwind(18)] +fn k16_pixel_shuffle_is_a_bijection() { + match kani::any::() % 4 { + 0 => shuffle_case(2, 1, 2, 2), + 1 => shuffle_case(2, 2, 1, 2), + 2 => shuffle_case(1, 2, 3, 2), + _ => shuffle_case(2, 1, 1, 1), + } +} + +/// `pixel_unshuffle` at one shape: the plan refuses a side `r` does not divide; +/// otherwise a bijection, and the element the text names. +fn unshuffle_case(r: usize, c: usize, h: usize, w: usize) { + let n = c * h * w; + let Ok((oh, ow)) = plan::unshuffle_sides(h as u64, w as u64, r as u64) else { + assert!(h % r != 0 || w % r != 0, "only a side r does not divide is refused"); + return; + }; + let (oh, ow) = (oh as usize, ow as usize); + let out = interp::k_pixel_unshuffle(&Tensor::new(c as u32, h as u32, w as u32, ids(n)), r, oh, ow); + is_permutation_of_ids(&out.data, n); + let (cc, y, x, i, j) = (range(0, c as u32 - 1) as usize, range(0, oh as u32 - 1) as usize, range(0, ow as u32 - 1) as usize, range(0, r as u32 - 1) as usize, range(0, r as u32 - 1) as usize); + assert_eq!(out.data[((cc * r * r + i * r + j) * oh + y) * ow + x], ((cc * h + y * r + i) * w + x * r + j) as i64); +} + +/// K16. `pixel_unshuffle` (§5.10) is a bijection, the inverse layout of +/// `pixel_shuffle`, and the run-time plan refuses a side `r` does not divide. Window: +/// the shapes below, planes up to 4×4. +#[kani::proof] +#[kani::unwind(18)] +fn k16_pixel_unshuffle_is_a_bijection() { + match kani::any::() % 4 { + 0 => unshuffle_case(2, 1, 4, 4), + 1 => unshuffle_case(2, 2, 2, 4), + 2 => unshuffle_case(1, 2, 3, 2), + _ => unshuffle_case(2, 1, 3, 4), + } +} + +fn any_order() -> [u8; 4] { + let o: [u8; 4] = kani::any(); + kani::assume(o.iter().all(|&v| v < 4) && o[0] != o[1] && o[0] != o[2] && o[0] != o[3] && o[1] != o[2] && o[1] != o[3] && o[2] != o[3]); + o +} + +/// `subpos_split` and `subpos_merge` at one shape and a symbolic order. +fn subpos_case(c: usize, h: usize, w: usize) { + let n = c * h * w; + let order = any_order(); + let (oh, ow) = (h / 2, w / 2); + let outs = interp::k_subpos_split(&Tensor::new(c as u32, h as u32, w as u32, ids(n)), &order, oh, ow); + let all: Vec = outs.iter().flat_map(|t| t.data.iter().copied()).collect(); + is_permutation_of_ids(&all, n); + let k = range(0, 3) as usize; + let (a, b) = ((order[k] >> 1) as usize, (order[k] & 1) as usize); + let (cc, y, x) = (range(0, c as u32 - 1) as usize, range(0, oh as u32 - 1) as usize, range(0, ow as u32 - 1) as usize); + assert_eq!(outs[k].data[(cc * oh + y) * ow + x], ((cc * h + 2 * y + a) * w + 2 * x + b) as i64); + let ins: Vec<&Tensor> = outs.iter().collect(); + let back = interp::k_subpos_merge(&ins, &order, h, w); + let e = range(0, n as u32 - 1) as usize; + assert!(back.data.len() == n && back.data[e] == e as i64, "merge undoes split"); +} + +/// K16. `subpos_split` (§5.10) is a bijection from its input onto its four outputs, +/// with `out_k[c][y][x] = in[c][2y + a_k][2x + b_k]`, and `subpos_merge` with the same +/// order undoes it. Window: one channel, a 2×4 plane, every order. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(18)] +fn k16_subpos_split_and_merge() { + subpos_case(1, 2, 4); +} + +/// K16. `pad_rep`, `crop_to` and `crop` (§5.10), once the run-time plan has passed: +/// every index they read is in range (the checker's bounds checks), and each output +/// element is the one the text names. `crop`'s operands are any values a scalar can +/// take; the plan refuses one that does not fit. Window: planes up to 4×4, one +/// channel. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(18)] +fn k16_pad_and_crop_read_in_range() { + let (h, w) = (range(1, 4) as usize, range(1, 4) as usize); + let n = h * w; + let x = Tensor::new(1, h as u32, w as u32, ids(n)); + // pad_rep + let m = range(1, 4) as u64; + let (ph, pw) = plan::pad_rep_sides(h as u64, w as u64, m).expect("small sides"); + let (ph, pw) = (ph as usize, pw as usize); + let p = interp::k_pad_rep(&x, ph, pw); + let (y, xx) = (range(0, ph as u32 - 1) as usize, range(0, pw as u32 - 1) as usize); + assert_eq!(p.data[y * pw + xx], (y.min(h - 1) * w + xx.min(w - 1)) as i64); + // crop: any start and length a scalar can give, through the run-time plan's rule. + let (y0, x0, ch, cw): (i64, i64, i64, i64) = (kani::any(), kani::any(), kani::any(), kani::any()); + if let (Ok(oh), Ok(ow)) = (plan::crop_side(y0 as i128, ch as i128, h as u64), plan::crop_side(x0 as i128, cw as i128, w as u64)) { + let cr = interp::crop(&x, y0 as usize, x0 as usize, oh as usize, ow as usize); + let (y, xx) = (range(0, oh as u32 - 1) as usize, range(0, ow as u32 - 1) as usize); + assert_eq!(cr.data[y * ow as usize + xx], ((y0 as usize + y) * w + x0 as usize + xx) as i64); + } else { + assert!(y0 < 0 || ch < 1 || y0 as i128 + ch as i128 > h as i128 || x0 < 0 || cw < 1 || x0 as i128 + cw as i128 > w as i128); + } + // crop_to: the plan accepts a ref no larger than the input. + let (rh, rw) = (range(1, h as u32) as usize, range(1, w as u32) as usize); + let ct = interp::crop(&x, 0, 0, rh, rw); + let (y, xx) = (range(0, rh as u32 - 1) as usize, range(0, rw as u32 - 1) as usize); + assert_eq!(ct.data[y * rw + xx], (y * w + xx) as i64); +} + +// ------------------------------------------------------------------------------ K31 + +/// K31. `WHG1` parsing (§10, load steps 1–6) is total: every file of up to 96 bytes is +/// parsed or refused (`model_mismatch` at a load step), and nothing panics. Window: +/// every byte string of length 0 to 96. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(100)] +fn k31_whg1_parse_is_total() { + let b: [u8; 96] = kani::any(); + let n: usize = kani::any(); + kani::assume(n <= 96); + match Graph::parse(&b[..n]) { + Ok(g) => assert!(!g.tensors.is_empty() && !g.ops.is_empty()), + Err(r) => assert_eq!(r.code, crate::code::Code::ModelMismatch), + } +} + +// ------------------------------------------------------------------------------ K33 + +/// An `rq` with no multiplier, one shift of 0 and no bias: valid over any channel count. +fn rq0() -> Rq { + Rq { round: Round::Floor, bias_kind: BiasKind::None, m_kind: 0, s_kind: 1, m_bytes: 0, b_bytes: 0, mult: vec![], shift: vec![0], bias: vec![] } +} + +/// K33. The run-time plan (§4, run step 3) for `conv` is total, and no shape it accepts +/// lets the operator index out of range: for every input size, kernel, stride and +/// padding in the window, `conv`'s shape rule refuses, or the kernel computes every +/// output at the sizes the rule gives, reading only inside its input and weights. +/// Window: one channel each way, planes up to 3×3, kernels up to 3×3, strides up to 2, +/// padding up to 1. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(10)] +fn k33_plan_conv() { + let (h, w) = (range(1, 3) as u64, range(1, 3) as u64); + let (kh, kw, sh, sw, ph, pw) = (range(1, 3) as u64, range(1, 3) as u64, range(1, 2) as u64, range(1, 2) as u64, range(0, 1) as u64, range(0, 1) as u64); + match plan::conv_sides(h, w, kh, kw, sh, sw, ph, pw) { + Ok((oh, ow)) => { + let x = Tensor::new(1, h as u32, w as u32, data((h * w) as usize)); + let u = |v: u64| v as usize; + let o = interp::k_conv(&x, 1, u(kh), u(kw), u(sh), u(sw), u(ph), u(pw), 1, &rq0(), &data(u(kh * kw)), u(oh), u(ow), 0, &mut interp::Quiet).expect("i8 values"); + assert_eq!(o.data.len() as u64, oh * ow); + } + Err(f) => assert!(f == plan::Fail::Shape && (h + 2 * ph < kh || w + 2 * pw < kw), "only a kernel larger than the padded input"), + } +} + +/// K33. The same for `conv_transpose`: its shape rule refuses only an empty crop, and +/// otherwise the kernel computes every output, reading only inside its input, its +/// weights and its uncropped plane. Window: one channel each way, planes up to 2×2, +/// kernels up to 3×3, strides up to 2, padding and output padding up to 1. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(10)] +fn k33_plan_conv_transpose() { + let (h, w) = (range(1, 2) as u64, range(1, 2) as u64); + let (kh, kw, sh, sw) = (range(1, 3) as u64, range(1, 3) as u64, range(1, 2) as u64, range(1, 2) as u64); + let (ph, pw, oph, opw) = (range(0, 1) as u64, range(0, 1) as u64, range(0, 1) as u64, range(0, 1) as u64); + let (uh, uw) = ((h - 1) * sh + kh + oph, (w - 1) * sw + kw + opw); + match plan::conv_t_sides(h, w, 1, kh, kw, sh, sw, ph, pw, oph, opw) { + Ok((oh, ow)) => { + let x = Tensor::new(1, h as u32, w as u32, data((h * w) as usize)); + let u = |v: u64| v as usize; + let o = interp::k_conv_t(&x, 1, u(kh), u(kw), u(sh), u(sw), u(ph), u(pw), u(oph), u(opw), &rq0(), &data(u(kh * kw)), u(oh), u(ow), 0, &mut interp::Quiet).expect("i8 values"); + assert!(oh == uh - 2 * ph && ow == uw - 2 * pw && o.data.len() as u64 == oh * ow); + } + Err(f) => assert!(f == plan::Fail::Shape && (uh <= 2 * ph || uw <= 2 * pw), "only an empty crop"), + } +} + +/// K33. The operators with a second input, a scalar or a reshape: `mul` (a `b` of `C` +/// or 1 channels, at the sizes the plan's equal-size rule accepts), `chunk_add`, +/// `split` (`start + count ≤ C`, a load rule), `chscale` (a row the scalar's range +/// allows), `gram` and `apply` (the shapes their rules accept): each kernel computes +/// every output, reading only inside its inputs. Window: up to 2 channels, planes up to +/// 2×2. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(10)] +fn k33_plan_multi_input() { + let c = 2usize; + let (h, w) = (range(1, 2) as usize, range(1, 2) as usize); + let a = Tensor::new(c as u32, h as u32, w as u32, data(c * h * w)); + match range(0, 5) { + 0 => { + let cb = if kani::any() { c } else { 1 }; + let b = Tensor::new(cb as u32, h as u32, w as u32, data(cb * h * w)); + assert!(interp::k_mul(&a, &b, &rq0(), 0, &mut interp::Quiet).is_ok()); + } + 1 => assert_eq!(interp::k_chunk_add(&a, 0).expect("i8").data.len(), h * w), + 2 => { + let (start, count) = (range(0, 1) as usize, range(1, 2)); + kani::assume(start + count as usize <= c); + assert_eq!(interp::k_split(&a, start, count).data.len(), count as usize * h * w); + } + 3 => { + let rows = range(1, 3) as usize; + let row = range(0, rows as u32 - 1) as usize; + let m = data(rows * c); + assert!(interp::k_chscale(&a, row, Round::HalfEven, 3, &m, 0, &mut interp::Quiet).is_ok()); + } + 4 => { + let groups = range(1, 2) as usize; + let b = Tensor::new(c as u32, h as u32, w as u32, data(c * h * w)); + assert_eq!(interp::k_gram(&a, &b, groups, &rq0(), 0, &mut interp::Quiet).expect("i8").data.len(), c * (c / groups)); + } + _ => { + let groups = range(1, 2) as usize; + let d = c / groups; + let att = Tensor::new(c as u32, 1, d as u32, data(c * d)); + assert_eq!(interp::k_apply(&att, &a, groups, &rq0(), 0, &mut interp::Quiet).expect("i8").data.len(), c * h * w); + } + } +} diff --git a/wai/wai-ops/src/proofs/rules.rs b/wai/wai-ops/src/proofs/rules.rs new file mode 100644 index 000000000..6251cd098 --- /dev/null +++ b/wai/wai-ops/src/proofs/rules.rs @@ -0,0 +1,61 @@ +//! The bound rules of §8.2–§8.3, restated from the text in `i128` for the soundness +//! harnesses. +//! +//! The bounds pass ([`crate::bounds`]) forms these intervals in 512-bit arithmetic +//! with saturation, which a model checker cannot execute on symbolic operands in +//! bounded time: every 512-bit product is 36 limb multiplications, and every +//! operation a loop over eight limbs. The soundness harnesses therefore take each +//! rule as §8.3 writes it, on operands small enough that no value here leaves `i128` +//! (each harness's window), and prove that every value the interpreter forms lies in +//! it. That the bounds pass computes these same rules is shown separately, and on +//! every graph the corpus holds: the independent certifier (`tools/wai_ops_check.py`, +//! written from the text alone) recomputes every certificate byte for byte. + +use crate::graph::Round; +use crate::interp::round; + +/// An interval `[lo, hi]`. +pub(crate) type R = (i128, i128); + +pub(crate) fn within(r: R, v: i128) -> bool { + r.0 <= v && v <= r.1 +} + +pub(crate) fn hull(a: R, b: R) -> R { + (a.0.min(b.0), a.1.max(b.1)) +} + +/// The term interval of a weight `w` over `[l, h]` (§8.2). +pub(crate) fn term(w: i128, x: R) -> R { + let (a, b) = (w * x.0, w * x.1); + (a.min(b), a.max(b)) +} + +/// The corner hull of two run-time intervals (§8.2). +pub(crate) fn corner(a: R, b: R) -> R { + let c = [a.0 * b.0, a.0 * b.1, a.1 * b.0, a.1 * b.1]; + (c[0].min(c[1]).min(c[2]).min(c[3]), c[0].max(c[1]).max(c[2]).max(c[3])) +} + +/// The partial-sum interval `A(K, b)` (§8.2), for the terms `ks` and the bias `b`. +pub(crate) fn psum(ks: &[R], b: i128) -> R { + let mut r = (b.min(0), b.max(0)); + for k in ks { + r = (r.0 + k.0.min(0), r.1 + k.1.max(0)); + } + r +} + +/// `⌊v / 2^s⌋` of both ends. +pub(crate) fn shr(r: R, s: u32) -> R { + (r.0 >> s, r.1 >> s) +} + +/// The `rq` rules (§8.3) from `rq.t`: `rq.p` (with `half_up`'s and `half_even`'s +/// addend), `rq.q` and `rq.y`. `R` is [`round`], which K3 proves equal to §2. +pub(crate) fn rq(t: R, m: i128, s: u32, r: Round, post: i128) -> (R, R, R) { + let p = term(m, t); + let a = if r != Round::Floor && s >= 1 { 1i128 << (s - 1) } else { 0 }; + let q = (round(p.0, s, r).expect("small values"), round(p.1, s, r).expect("small values")); + ((p.0, p.1 + a), q, (q.0 + post, q.1 + post)) +} diff --git a/wai/wai-ops/src/proofs/sound.rs b/wai/wai-ops/src/proofs/sound.rs new file mode 100644 index 000000000..a9220029b --- /dev/null +++ b/wai/wai-ops/src/proofs/sound.rs @@ -0,0 +1,584 @@ +//! Soundness of the bound rules of §8.3: every value the interpreter forms lies in the +//! interval the rule gives it. K4, K9, K11, K14, K18–K22. +//! +//! Each harness runs one operator's kernel ([`crate::interp`]'s `k_*`) on symbolic +//! inputs inside a symbolic input interval, and holds every value the kernel reports +//! (its named intermediates, §8.5's Table 8.5-A) and every output to the interval §8.3's +//! rule gives it, restated in [`super::rules`]. Where a rule bounds partial sums +//! (`A(K, b)`, §8.2), a second harness takes every set of terms one output position can +//! hold, with or without the bias: every partial sum, in every order and grouping, and +//! the sum at a position where padding removes taps, is such a subset sum. +//! +//! The kernels take their shapes as arguments, so the convolution harnesses run them at +//! concrete shapes, which the checker unrolls exactly; the shape-free harnesses cover +//! the rest of each window. + +use alloc::vec; +use alloc::vec::Vec; + +use super::rules::{R, corner, hull, psum, rq, shr, term, within}; +use super::{Keyed, Rec, any_round}; +use crate::graph::{BiasKind, Round, Rq}; +use crate::interp::{self, Tensor}; + +/// A symbolic value in `[lo, hi]`. +fn any_in(lo: i64, hi: i64) -> i64 { + let v: i64 = kani::any(); + kani::assume(lo <= v && v <= hi); + v +} + +/// `n` symbolic `i8` values in `[l, h]`, as `i64`. +fn i8s_in(n: usize, l: i8, h: i8) -> Vec { + let raw: [i8; 18] = kani::any(); + kani::assume(raw[..n].iter().all(|&v| l <= v && v <= h)); + raw[..n].iter().map(|&v| v as i64).collect() +} + +/// An `rq` that leaves its input as it is apart from a `pre` bias `b`: no multiplier, +/// shift 0. Its output is then the accumulator plus `b`. +fn identity_rq(b: i64, c: usize) -> Rq { + Rq { round: Round::Floor, bias_kind: BiasKind::Pre, m_kind: 0, s_kind: 1, m_bytes: 0, b_bytes: 8, mult: vec![], shift: vec![0], bias: vec![b; c] } +} + +/// `rq` with no multiplier, no bias, one shift: the contractions' (§5.9). +fn plain_rq(r: Round, s: u8) -> Rq { + Rq { round: r, bias_kind: BiasKind::None, m_kind: 0, s_kind: 1, m_bytes: 0, b_bytes: 0, mult: vec![], shift: vec![s], bias: vec![] } +} + +// ------------------------------------------------------------------------------ K14 + +/// K14. `leaky` (§5.5, §8.3): a negative input's product `v·a` lies in `leaky.p`, and is +/// floored (`⌊v·a / 2^f⌋`, toward −∞); every output lies in the producer result. +/// Window: every interval `[l, h]` and value in it, and every `a`, within `i32`; every +/// `f` in `0..=63`. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(4)] +fn k14_leaky_bounds_sound() { + let (l, h, a): (i32, i32, i32) = (kani::any(), kani::any(), kani::any()); + leaky_case(l, h, a); +} + +/// K14 with the interval, the value and `a` within `i16`: the same statement on a +/// narrower window. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(4)] +fn k14_leaky_bounds_sound_i16() { + let (l, h, a): (i16, i16, i16) = (kani::any(), kani::any(), kani::any()); + leaky_case(l as i32, h as i32, a as i32); +} + +/// K14 with the interval, the value and `a` within `i8`. +#[kani::proof] +#[kani::unwind(4)] +fn k14_leaky_bounds_sound_i8() { + let (l, h, a): (i8, i8, i8) = (kani::any(), kani::any(), kani::any()); + leaky_case(l as i32, h as i32, a as i32); +} + +fn leaky_case(l: i32, h: i32, a: i32) { + kani::assume(l <= h); + let v = any_in(l as i64, h as i64); + let f: u32 = kani::any(); + kani::assume(f <= 63); + // §8.3's rule, in i64: every product of two i32 values fits. + let (li, hi, ai) = (l as i64, h as i64, a as i64); + let (c1, c2) = (li * ai, hi.min(-1) * ai); + let p = (c1.min(c2) as i128, c1.max(c2) as i128); + let mut res: Option = if li < 0 { Some(shr(p, f)) } else { None }; + if hi >= 0 { + let nn = (li.max(0) as i128, hi as i128); + res = Some(res.map_or(nn, |r| hull(r, nn))); + } + let res = res.expect("one part is present"); + // leaky reports leaky.p, for a negative input only. + let mut rec = Rec::new(); + let out = interp::k_leaky(&Tensor::new(1, 1, 1, vec![v]), a as i64, f, 0, &mut rec).expect("leaky is total"); + let y = out.data[0] as i128; + assert!(within(res, y), "the output lies in the producer result"); + if v < 0 { + assert_eq!(rec.n, 1); + let pv = rec.v[0]; + assert!(within(p, pv), "v·a lies in leaky.p"); + assert!(y * (1i128 << f) <= pv && pv < (y + 1) * (1i128 << f), "the product is floored"); + } else { + assert_eq!(rec.n, 0); + assert_eq!(y, v as i128); + } +} + +// ------------------------------------------------------------------------------- K4 + +/// The term interval of an `i8` weight over an `i8` interval, and `A(K, b)`, in `i32` +/// (every value here is at most 18·2^14 in magnitude): §8.2's formulas. +fn term32(w: i32, l: i32, h: i32) -> (i32, i32) { + let (a, b) = (w * l, w * h); + (a.min(b), a.max(b)) +} + +/// K4 and K9, first lemma: a term lies in its term interval (§8.2). For every weight, +/// interval and value in `i8`, `w·x` lies in `[min(w·l, w·h), max(w·l, w·h)]`. +#[kani::proof] +fn k04_term_lies_in_its_interval() { + let (w, l, h, x): (i8, i8, i8, i8) = (kani::any(), kani::any(), kani::any(), kani::any()); + kani::assume(l <= x && x <= h); + let (lo, hi) = term32(w as i32, l as i32, h as i32); + let t = w as i32 * x as i32; + assert!(lo <= t && t <= hi, "w·x lies in its term interval"); +} + +/// K4 and K9, second lemma: `A(K, b)` (§8.2) holds every partial sum, by induction on +/// the terms. Base: with no term, a partial sum is 0 or the bias `b`, and both lie in +/// `[min(0, b), max(0, b)]`. Step: if a partial sum `s` lies in `[lo, hi]` and a term +/// `t` lies in its interval `[l, h]`, then `s` and `s + t` both lie in +/// `[lo + min(0, l), hi + max(0, h)]`. So every subset sum of any number of terms, with +/// or without the bias, lies in `A(K, b)`: the taps one position reads, in every order +/// and with padding removing any of them, and for `conv_transpose` the taps of one +/// residue class (`k09_conv_transpose_residues`). With the first lemma, every partial +/// sum of every output position lies in `conv.acc` and `convT.acc`. Window: every +/// value in `i32` (the step's sums are formed in `i64`). +#[kani::proof] +fn k04_partial_sums_lie_in_a() { + let b: i32 = kani::any(); + let s0: i64 = if kani::any() { b as i64 } else { 0 }; + assert!((b as i64).min(0) <= s0 && s0 <= (b as i64).max(0), "base"); + let (s, lo, hi, t, l, h): (i32, i32, i32, i32, i32, i32) = (kani::any(), kani::any(), kani::any(), kani::any(), kani::any(), kani::any()); + kani::assume(lo <= s && s <= hi && l <= t && t <= h); + let (lo2, hi2) = (lo as i64 + (l as i64).min(0), hi as i64 + (h as i64).max(0)); + let (s, t) = (s as i64, t as i64); + assert!(lo2 <= s && s <= hi2, "a sum without the term stays in the wider interval"); + assert!(lo2 <= s + t && s + t <= hi2, "a sum with the term lies in the wider interval"); +} + +/// K4. The interpreter's `conv` at a concrete shape — two input channels, one output +/// channel, a 3×3 kernel with padding 1 on a 3×3 plane, so positions on the edge lose +/// taps — with symbolic `i8` weights, bias, interval and inputs: every term it forms +/// lies in `conv.term`, and every partial sum, the accumulator with its bias, and every +/// output, in `conv.acc`. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(20)] +fn k04_conv_interpreter_stays_in_the_rule() { + let (l, h): (i8, i8) = (kani::any(), kani::any()); + kani::assume(l <= h); + let w = i8s_in(18, i8::MIN, i8::MAX); + let x = i8s_in(18, l, h); + let b: i8 = kani::any(); + let terms: Vec = w.iter().map(|&wv| term(wv as i128, (l as i128, h as i128))).collect(); + let conv_term = terms.iter().copied().reduce(hull).expect("taps"); + let acc = psum(&terms, b as i128); + let mut obs = Keyed { rules: [("conv.term", conv_term), ("conv.acc", acc), ("rq.t", acc), ("rq.p", acc), ("rq.q", acc), ("rq.y", acc)], seen: 0 }; + let out = interp::k_conv(&Tensor::new(2, 3, 3, x), 1, 3, 3, 1, 1, 1, 1, 1, &identity_rq(b as i64, 1), &w, 3, 3, 0, &mut obs).expect("conv on i8 values is formed"); + assert!(obs.seen > 0); + for &v in &out.data { + assert!(within(acc, v as i128), "every output lies in conv.acc"); + } +} + +// ------------------------------------------------------------------------------- K9 + +/// K9. The residue-class rule of `conv_transpose` (§8.3): one output position reads the +/// taps of one residue only. For every output row `y`, padding `ph ≤ 2`, stride +/// `sh ≤ 3` and kernel row `i < 3`, a tap that §5.3's gather form gives position `y` +/// (`ty = y + ph − i ≥ 0`, `ty mod sh = 0`) has `i mod sh = (y + ph) mod sh`. Columns +/// are the same statement. A position's partial sums are therefore partial sums of one +/// `K_ρ`, which `k04_partial_sums_lie_in_a` puts in `A(K_ρ, b)`, and so in `convT.acc`, +/// the hull over residues. +#[kani::proof] +fn k09_conv_transpose_residues() { + let (y, ph, sh, i): (u32, u32, u32, u32) = (kani::any(), kani::any(), kani::any(), kani::any()); + kani::assume(y <= 64 && ph <= 2 && (1..=3).contains(&sh) && i < 3); + let ty = (y + ph) as i64 - i as i64; + if ty >= 0 && ty % sh as i64 == 0 { + assert_eq!(i % sh, (y + ph) % sh, "a position reads the taps of one residue"); + } +} + +/// `convT.acc` for one channel each way: the hull over residues `ρ` of `A(K_ρ, b)`. +fn convt_acc(w: &[i64], kh: usize, kw: usize, sh: usize, sw: usize, x: R, b: i128) -> (R, R) { + let terms: Vec = w.iter().map(|&wv| term(wv as i128, x)).collect(); + let all = terms.iter().copied().reduce(hull).expect("taps"); + let mut acc: Option = None; + for ry in 0..sh { + for rx in 0..sw { + let mut ks: Vec = Vec::new(); + for i in 0..kh { + for j in 0..kw { + if i % sh == ry && j % sw == rx { + ks.push(terms[i * kw + j]); + } + } + } + let a = psum(&ks, b); + acc = Some(acc.map_or(a, |r| hull(r, a))); + } + } + (all, acc.expect("a residue")) +} + +/// K9. The interpreter's `conv_transpose` at two concrete shapes — 3×3 kernels, stride +/// 2 with padding 1 and output padding 1, and stride 3 with no padding, on 2×2 planes — +/// with symbolic `i8` weights, bias, interval and inputs: every product it forms lies +/// in `convT.term`, and every partial sum of every cell, the accumulator with its bias, +/// and every output, in `convT.acc`. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(12)] +fn k09_conv_transpose_interpreter_stays_in_the_rule() { + let (l, h): (i8, i8) = (kani::any(), kani::any()); + kani::assume(l <= h); + let w = i8s_in(9, i8::MIN, i8::MAX); + let x = i8s_in(4, l, h); + let b: i8 = kani::any(); + let (s, p, op) = if kani::any() { (2usize, 1usize, 1usize) } else { (3, 0, 0) }; + let (all, acc) = convt_acc(&w, 3, 3, s, s, (l as i128, h as i128), b as i128); + let o = (2 - 1) * s + 3 + op - 2 * p; + let mut obs = Keyed { rules: [("convT.term", all), ("convT.acc", acc), ("rq.t", acc), ("rq.p", acc), ("rq.q", acc), ("rq.y", acc)], seen: 0 }; + let out = interp::k_conv_t(&Tensor::new(1, 2, 2, x), 1, 3, 3, s, s, p, p, op, op, &identity_rq(b as i64, 1), &w, o, o, 0, &mut obs).expect("formed"); + for &v in &out.data { + assert!(within(acc, v as i128), "every output lies in convT.acc"); + } +} + +// ------------------------------------------------------------------------------ K11 + +/// K11. `igdn` (§5.7, §8.3), first part: the values the interpreter forms up to the +/// final norm lie in the rule's intervals — `x_j²` in `igdn.x2`, each `γ·x_j²` in +/// `igdn.gx2`, each floored term in `igdn.term`, every partial sum of `N_i` (with or +/// without `β_i`) in `igdn.N` — and the final norm `N_i` in the rule's final-norm +/// interval `Nf_i`, from which the rule takes `igdn.r`. The rest of the rule follows +/// from the three lemmas below and K3: `r_i = isqrt(max(0, N_i))` lies in +/// `[isqrt(max(0, Nf_lo)), isqrt(max(0, Nf_hi))]` because `isqrt` is non-decreasing; +/// `x_i·r_i` lies in the corner hull `igdn.xr`; and the output, its floor shift, in the +/// producer result, because `R_floor` is non-decreasing. Window: `C ≤ 2`, `x` and `γ` +/// in `i8`, `β` in `i16`, `gf` up to 8. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(6)] +fn k11_igdn_bounds_sound() { + if kani::any() { igdn_case(1, 0) } else if kani::any() { igdn_case(2, 0) } else { igdn_case(2, 1) } +} + +/// K11's first part at `c` channels, for output channel `i`. +fn igdn_case(c: usize, i: usize) { + let (l, h): (i8, i8) = (kani::any(), kani::any()); + kani::assume(l <= h); + let data = i8s_in(c, l, h); + let gamma = i8s_in(c * c, i8::MIN, i8::MAX); + let braw: [i16; 2] = kani::any(); + let beta: Vec = braw[..c].iter().map(|&v| v as i64).collect(); + let gf: u32 = kani::any(); + kani::assume(gf <= 8); + // §8.3's rule, for output channel i. + let (li, hi) = (l as i128, h as i128); + let x2 = if li <= 0 && 0 <= hi { (0, (li * li).max(hi * hi)) } else { ((li * li).min(hi * hi), (li * li).max(hi * hi)) }; + let terms: Vec = (0..c).map(|j| corner((gamma[i * c + j] as i128, gamma[i * c + j] as i128), x2)).collect(); + let floored: Vec = terms.iter().map(|&t| shr(t, gf)).collect(); + let n_rule = psum(&floored, beta[i] as i128); + let nf = floored.iter().fold((beta[i] as i128, beta[i] as i128), |a, t| (a.0 + t.0, a.1 + t.1)); + // igdn reports, at one position: x_j² for each j; then for each output channel: + // N = β, and for each j γ·x_j², the floored term and N; then r and x·r. + let mut rec = Rec::new(); + let _ = interp::k_igdn(&Tensor::new(c as u32, 1, 1, data), gf, 0, &gamma, &beta, 0, &mut rec).expect("igdn on i8 inputs is formed"); + assert_eq!(rec.n, c + c * (3 + 3 * c)); + for j in 0..c { + assert!(within(x2, rec.v[j]), "x_j² lies in igdn.x2"); + } + let base = c + i * (3 + 3 * c); + assert!(within(n_rule, rec.v[base]), "β alone lies in igdn.N"); + let pick: [bool; 2] = kani::any(); + let mut partial: i128 = if kani::any() { beta[i] as i128 } else { 0 }; + for j in 0..c { + let (gx2, t, n) = (rec.v[base + 1 + 3 * j], rec.v[base + 2 + 3 * j], rec.v[base + 3 + 3 * j]); + assert!(within(terms[j], gx2), "γ·x_j² lies in igdn.gx2"); + assert!(within(floored[j], t), "the floored term lies in igdn.term"); + assert!(within(n_rule, n), "the running norm lies in igdn.N"); + if pick[j] { + partial += t; + } + } + assert!(within(n_rule, partial), "every partial sum of N_i lies in igdn.N"); + assert!(within(nf, rec.v[base + 3 * c]), "the final norm lies in Nf_i"); +} + +/// K11, second lemma: `isqrt` (the interpreter's) is non-decreasing. Window: every +/// `a ≤ b` below 2^32 (the norms of K11's window are below 2^23). +#[kani::proof] +fn k11_isqrt_is_monotone() { + let (a, b): (u32, u32) = (kani::any(), kani::any()); + kani::assume(a <= b); + assert!((a as u128).isqrt() <= (b as u128).isqrt()); +} + +/// K11 (and every rule that takes a corner hull, §8.2), third lemma: for `x ∈ [l, h]` +/// and `r ∈ [a, b]`, `x·r` lies in the corner hull of the two intervals. Window: every +/// value in `i8`. +#[kani::proof] +fn k11_corner_hull_holds_products() { + let (l, h, x, a, b, r): (i8, i8, i8, i8, i8, i8) = (kani::any(), kani::any(), kani::any(), kani::any(), kani::any(), kani::any()); + kani::assume(l <= x && x <= h && a <= r && r <= b); + let (l, h, x, a, b, r) = (l as i32, h as i32, x as i32, a as i32, b as i32, r as i32); + let c = [l * a, l * b, h * a, h * b]; + let (lo, hi) = (c[0].min(c[1]).min(c[2]).min(c[3]), c[0].max(c[1]).max(c[2]).max(c[3])); + assert!(lo <= x * r && x * r <= hi, "x·r lies in the corner hull"); +} + +// ------------------------------------------------------------------------------ K19 + +/// K19. `sigmoid` (§5.8): for every `v` in `i64` but `−2^63` (which `exp.negx` excludes), +/// the output lies in `[0, 2^16]` — the producer result — and the dividend `sig.num` +/// (`2^32`, or `e·2^16`) lies in `[0, 65553·2^16]`. +#[kani::proof] +#[kani::unwind(4)] +fn k19_sigmoid_ranges() { + let v: i64 = kani::any(); + kani::assume(v > i64::MIN); + // sigmoid reports exp.negx, exp.nl, exp.t2, exp.c, then sig.num. + let mut rec = Rec::new(); + let out = interp::k_sigmoid(&Tensor::new(1, 1, 1, vec![v]), 0, &mut rec).expect("sigmoid is total"); + assert_eq!(rec.n, 5); + let y = out.data[0] as i128; + assert!((0..=1 << 16).contains(&y), "the output lies in [0, 2^16]"); + assert!((0..=65553 << 16).contains(&rec.v[4]), "sig.num lies in [0, 65553·2^16]"); +} + +/// K19. `elu(α)` (§5.8): for every interval `[l, h]` and `v` in it within `i64` (with +/// `exp.negx = −v` fitting `i64`), and every `α` in `i64` whose producer result fits +/// `i64` (every certified graph's): `α·(e − 2^16)` lies in `elu.p`, the corner hull of +/// `[α, α]` and `[−2^16, 17]`, and the output in the producer result. +#[kani::proof] +#[kani::unwind(4)] +fn k19_elu_ranges() { + let (l, h): (i64, i64) = (kani::any(), kani::any()); + kani::assume(l > i64::MIN && l <= h); + let v = any_in(l, h); + let alpha: i64 = kani::any(); + let ai = alpha as i128; + let elu_p = corner((ai, ai), (-(1 << 16), 17)); + let mut res: Option = if h > 0 { Some(((l as i128).max(1), h as i128)) } else { None }; + if l <= 0 { + let q = shr(elu_p, 16); + res = Some(res.map_or(q, |r| hull(r, q))); + } + let res = res.expect("one part is present"); + // A certified graph: its producer result fits i64 (acc64's `tensor` class). With + // α = −2^63 the result reaches 2^63, and load step 8 refuses the graph. + kani::assume(i64::try_from(res.0).is_ok() && i64::try_from(res.1).is_ok()); + // elu reports, for v ≤ 0, exp.negx, exp.nl, exp.t2, exp.c, then elu.p. + let mut rec = Rec::new(); + let out = interp::k_elu(&Tensor::new(1, 1, 1, vec![v]), alpha, 0, &mut rec).expect("elu is formed for every certified input"); + let y = out.data[0] as i128; + assert!(within(res, y), "the output lies in the producer result"); + if v <= 0 { + assert_eq!(rec.n, 5); + assert!(within(elu_p, rec.v[4]), "α·(e − 2^16) lies in elu.p"); + } else { + assert_eq!(rec.n, 0); + } +} + +// ------------------------------------------------------------------------------ K22 + +/// K22. `gram` (§5.9, §8.3): every term `A·B` lies in `gram.term`, every partial sum in +/// `gram.acc`, `rq.p`, `rq.q` and `rq.y` in their intervals, and the output in the +/// producer result. Window: `C = 2` in one or two groups, `H·W = 2` (the largest the +/// declared sizes allow), `i8` values, any rounding, shifts up to 8. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(12)] +fn k22_gram_bounds_sound() { + let groups: usize = if kani::any() { 1 } else { 2 }; + let (la, ha, lb, hb): (i8, i8, i8, i8) = (kani::any(), kani::any(), kani::any(), kani::any()); + kani::assume(la <= ha && lb <= hb); + let a = i8s_in(4, la, ha); + let b = i8s_in(4, lb, hb); + let s: u8 = kani::any(); + kani::assume(s <= 8); + let r = any_round(); + // §8.3's rule, with L = 2. + let gt = corner((la as i128, ha as i128), (lb as i128, hb as i128)); + let gacc = (2 * gt.0.min(0), 2 * gt.1.max(0)); + let (p_rule, q_rule, y_rule) = rq(gacc, 1, s as u32, r, 0); + let mut obs = Keyed { rules: [("gram.term", gt), ("gram.acc", gacc), ("rq.t", gacc), ("rq.p", p_rule), ("rq.q", q_rule), ("rq.y", y_rule)], seen: 0 }; + let out = interp::k_gram(&Tensor::new(2, 1, 2, a), &Tensor::new(2, 1, 2, b), groups, &plain_rq(r, s), 0, &mut obs).expect("gram is formed"); + assert!(obs.seen > 0); + for &v in &out.data { + assert!(within(y_rule, v as i128), "the output lies in the producer result"); + } +} + +/// K22. `apply` (§5.9, §8.3): every term `A·V` lies in `apply.term`, every partial sum +/// in `apply.acc`, `rq.p`, `rq.q` and `rq.y` in their intervals, and the output in the +/// producer result. Window: `C = 2` in one or two groups, `V` of `H·W = 2`, `i8` values, +/// any rounding, shifts up to 8. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(12)] +fn k22_apply_bounds_sound() { + let groups: usize = if kani::any() { 1 } else { 2 }; + let d = 2 / groups; + let (la, ha, lv, hv): (i8, i8, i8, i8) = (kani::any(), kani::any(), kani::any(), kani::any()); + kani::assume(la <= ha && lv <= hv); + let a = i8s_in(2 * d, la, ha); + let v = i8s_in(4, lv, hv); + let s: u8 = kani::any(); + kani::assume(s <= 8); + let r = any_round(); + let at = corner((la as i128, ha as i128), (lv as i128, hv as i128)); + let aacc = (d as i128 * at.0.min(0), d as i128 * at.1.max(0)); + let (p_rule, q_rule, y_rule) = rq(aacc, 1, s as u32, r, 0); + let mut obs = Keyed { rules: [("apply.term", at), ("apply.acc", aacc), ("rq.t", aacc), ("rq.p", p_rule), ("rq.q", q_rule), ("rq.y", y_rule)], seen: 0 }; + let out = interp::k_apply(&Tensor::new(2, 1, d as u32, a), &Tensor::new(2, 1, 2, v), groups, &plain_rq(r, s), 0, &mut obs).expect("apply is formed"); + assert!(obs.seen > 0); + for &v in &out.data { + assert!(within(y_rule, v as i128), "the output lies in the producer result"); + } +} + +// ------------------------------------------------------------------------------ K18 + +/// K18. `softmax` (§5.7): over a row of `W ≤ 4` values whose spread `max − min` fits +/// `i64` (`sm.diff`'s class, which `acc64` certifies), every output lies in +/// `[0, 2^16]`, and the denominator `Σ = Σ_x exp_neg_q16(v_x − m)` is at least 65553 +/// (so the division is defined) and at most `W·65553` (`sm.sum`); each numerator lies +/// in `sm.num`. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(6)] +fn k18_softmax_ranges() { + softmax_case(4); +} + +/// K18 on rows of up to 2 values: the same statement on a narrower window. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(6)] +fn k18_softmax_ranges_w2() { + softmax_case(2); +} + +fn softmax_case(wmax: u32) { + let w: u32 = kani::any(); + kani::assume((1..=wmax).contains(&w)); + let raw: [i64; 4] = kani::any(); + let row = &raw[..w as usize]; + let m = *row.iter().max().unwrap(); + let mn = *row.iter().min().unwrap(); + kani::assume(i64::try_from(m as i128 - mn as i128).is_ok()); + // softmax reports, for each element of the row: sm.diff, exp.negx, exp.nl, exp.t2, + // exp.c and the running sum sm.sum; then each numerator sm.num. + let mut rec = Rec::new(); + let out = interp::k_softmax(&Tensor::new(1, 1, w, row.to_vec()), 0, &mut rec).expect("softmax is formed"); + let w = w as usize; + assert_eq!(rec.n, 7 * w); + let sum = rec.v[6 * w - 1]; + assert!(sum >= 65553, "Σ ≥ 65553: the largest element contributes exp_neg_q16(0)"); + assert!(sum <= w as i128 * 65553, "Σ lies in sm.sum"); + for k in 0..w { + assert!((0..=65553 * 65536 + (w as i128 * 65553) / 2).contains(&rec.v[6 * w + k]), "sm.num lies in its interval"); + assert!((0..=1 << 16).contains(&out.data[k]), "every output lies in [0, 2^16]"); + } +} + +// ------------------------------------------------------------------------------ K20 + +/// K20. Lemma L1 (`layernorm_c`, §8.3): `|n_c| ≤ N`, the bound the rule records as +/// `ln.n` — `N = min(⌊(h − l)·⌊2^32/r0⌋ / 2^16⌋ + 1, N_max)` with +/// `N_max = ⌊isqrt_ceil(C)·2^16·(r0 + 1) / r0⌋ + 1` and `r0 = isqrt(ε)` — and +/// `U = V + ε` is held in 128 bits. Window: `C ≤ 3`, inputs within `±2^10` (the +/// declared range), any `ε` in `1..=2^64 − 1`. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(6)] +fn k20_layernorm_lemma_l1() { + let eps: u64 = kani::any(); + kani::assume(eps >= 1); + lemma_l1(eps); +} + +/// K20 with `ε` in `1..=2^31 − 1`: the same statement on a narrower `ε`. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(6)] +fn k20_layernorm_lemma_l1_eps_u31() { + let eps: u32 = kani::any(); + kani::assume(eps >= 1 && eps < 1 << 31); + lemma_l1(eps as u64); +} + +fn lemma_l1(eps: u64) { + let c: u32 = kani::any(); + kani::assume((1..=3).contains(&c)); + let raw: [i16; 3] = kani::any(); + kani::assume(raw.iter().all(|&v| (-1024..=1024).contains(&v))); + let xs: Vec = raw[..c as usize].iter().map(|&v| v as i64).collect(); + let (graw, braw): ([i8; 3], [i8; 3]) = (kani::any(), kani::any()); + let gamma: Vec = graw[..c as usize].iter().map(|&v| v as i64).collect(); + let beta: Vec = braw[..c as usize].iter().map(|&v| v as i64).collect(); + // §8.3's ln.n, on the declared range [−2^10, 2^10]. + let r0 = (eps as u128).isqrt() as i128; + let ic = match c { + 1 => 1, + _ => 2, + }; // isqrt_ceil(C) for C ≤ 3 + let nmax = ic * (1 << 16) * (r0 + 1) / r0 + 1; + let k32 = (1i128 << 32) / r0; + let n_rule = (((2048 * k32) >> 16) + 1).min(nmax); + // layernorm_c reports, at one position: ln.S for each channel, ln.m, then ln.d and + // ln.T for each channel, ln.v (U = V + ε, formed in i128), rsq.num and ln.k; then + // ln.dk, ln.n and ln.ng for each channel. + let mut rec = Rec::new(); + let _ = interp::k_layernorm(&Tensor::new(c, 1, 1, xs), eps, &gamma, &beta, 0, &mut rec).expect("layernorm_c is formed: U = V + ε is held in 128 bits"); + let c = c as usize; + assert_eq!(rec.n, 6 * c + 4); + let j: usize = kani::any(); + kani::assume(j < c); + let n = rec.v[3 * c + 4 + 3 * j + 1]; + assert!(-n_rule <= n && n <= n_rule, "|n_c| ≤ N (lemma L1)"); +} + +// ------------------------------------------------------------------------------ K21 + +/// K21. Lemma L2 (`l2norm`, §8.3): `|v·k| ≤ 2^32`, so every output lies in +/// `[−2^16, 2^16]`, the producer result. Window: `L ≤ 4` positions, values within +/// `±2^20`, any `ε` in `1..=2^64 − 1`. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(6)] +fn k21_l2norm_lemma_l2() { + let eps: u64 = kani::any(); + kani::assume(eps >= 1); + lemma_l2(eps, 1 << 20); +} + +/// K21 with `ε` in `1..=2^20` and values within `±2^10`: the same statement on a +/// narrower window. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(6)] +fn k21_l2norm_lemma_l2_small() { + let eps: u32 = kani::any(); + kani::assume(eps >= 1 && eps <= 1 << 20); + lemma_l2(eps as u64, 1 << 10); +} + +fn lemma_l2(eps: u64, lim: i32) { + let len: u32 = kani::any(); + kani::assume((1..=4).contains(&len)); + let raw: [i32; 4] = kani::any(); + kani::assume(raw.iter().all(|&v| (-lim..=lim).contains(&v))); + let xs: Vec = raw[..len as usize].iter().map(|&v| v as i64).collect(); + // l2norm reports, for its one channel: l2.T for each position, then U, rsq.num and + // l2.k; then l2.vk for each position. + let mut rec = Rec::new(); + let out = interp::k_l2norm(&Tensor::new(1, 1, len, xs), eps, 0, &mut rec).expect("l2norm is formed"); + let len = len as usize; + assert_eq!(rec.n, 2 * len + 3); + for j in 0..len { + let vk = rec.v[len + 3 + j]; + assert!(-(1i128 << 32) <= vk && vk <= 1i128 << 32, "|v·k| ≤ 2^32 (lemma L2)"); + assert!((-(1 << 16)..=1 << 16).contains(&out.data[j]), "the output lies in [−2^16, 2^16]"); + } +} diff --git a/wai/wai-ops/src/proofs/stage.rs b/wai/wai-ops/src/proofs/stage.rs new file mode 100644 index 000000000..a73ca4849 --- /dev/null +++ b/wai/wai-ops/src/proofs/stage.rs @@ -0,0 +1,467 @@ +//! The stage operators of §5E: K23–K30. + +use alloc::vec; +use alloc::vec::Vec; + +use crate::code::Code; +use crate::interp::Tensor; +use crate::stage::mans::{self, Span, Win}; +use crate::stage::rans64::{self, End, Escape, Modes, StageRefusal, Table, TableRule}; +use crate::stage::{band_lookup, block_stat, bucket_ceil, bucket_floor, i32_form_fits, residual_step, residual_step_i32, scale_index}; + +// ------------------------------------------------------------------------------ K23 + +/// K23. `bucket` (E3), rule `ceil`: for any `N ≤ 4` edges and any `σ`, the index lies in +/// `[0, N − 1]`, and it is non-decreasing in `σ`. Window: every edge table of up to 4 +/// `i64` edges, ordered or not, and every pair `σ₁ ≤ σ₂`. +#[kani::proof] +#[kani::unwind(6)] +fn k23_bucket_ceil_in_range_and_monotone() { + let e: [i64; 4] = kani::any(); + let n: usize = kani::any(); + kani::assume((1..=4).contains(&n)); + let (a, b): (i64, i64) = (kani::any(), kani::any()); + kani::assume(a <= b); + let ia = bucket_ceil(a, &e[..n]).expect("N ≥ 1 edges give an index"); + let ib = bucket_ceil(b, &e[..n]).expect("N ≥ 1 edges give an index"); + assert!(ia < n && ib < n, "the index lies in [0, N − 1]"); + assert!(ia <= ib, "non-decreasing in σ"); +} + +/// K23. `bucket`, rule `floor`: for `N − 1 ≤ 3` non-decreasing edges (the load check) +/// and any `σ`, the index `#{i : e_i ≤ σ}` lies in `[0, N − 1]` and is non-decreasing in +/// `σ`; edges that decrease are refused. Window: every table of up to 3 `i64` edges. +#[kani::proof] +#[kani::unwind(6)] +fn k23_bucket_floor_in_range_and_monotone() { + let e: [i64; 3] = kani::any(); + let m: usize = kani::any(); + kani::assume((1..=3).contains(&m)); + let (a, b): (i64, i64) = (kani::any(), kani::any()); + kani::assume(a <= b); + let ordered = e[..m].windows(2).all(|p| p[0] <= p[1]); + match (bucket_floor(a, &e[..m]), bucket_floor(b, &e[..m])) { + (Some(ia), Some(ib)) => { + assert!(ordered, "only a non-decreasing table gives an index"); + assert!(ia <= m && ib <= m, "the index lies in [0, N − 1]"); + assert!(ia <= ib, "non-decreasing in σ"); + } + (None, None) => assert!(!ordered, "a non-decreasing table is never refused"), + _ => panic!("the load check does not depend on σ"), + } +} + +// --------------------------------------------------------------- rANS, from the text + +/// integer-payloads §2's decoder, written from the text for K24–K26: the state, the +/// renormalisation, `bits` and the table step, over a stream of `L` bytes. +struct Model<'a> { + s: &'a [u8], + idx: usize, + x: u64, + out: bool, +} + +impl<'a> Model<'a> { + fn word(&self, k: usize) -> u64 { + u32::from_le_bytes([self.s[4 * k], self.s[4 * k + 1], self.s[4 * k + 2], self.s[4 * k + 3]]) as u64 + } + fn new(s: &'a [u8]) -> Model<'a> { + let mut m = Model { s, idx: 2, x: 0, out: false }; + m.x = (m.word(1) << 32) | m.word(0); + m + } + /// If `x < 2^31`: `x = (x << 32) | w` with the next unread word, or, with none left, + /// the stream has run out and `x` stays. + fn renorm(&mut self) { + if self.x < 1 << 31 { + if 4 * self.idx + 4 <= self.s.len() { + self.x = (self.x << 32) | self.word(self.idx); + self.idx += 1; + } else { + self.out = true; + } + } + } + fn bits(&mut self, n: u32) -> u64 { + let v = self.x % (1 << n); + self.x >>= n; + self.renorm(); + v + } + /// The table step against `cdf = [0, 2^15, 2^16]`: both symbols have frequency + /// `2^15`. Returns `s`. + fn half_table(&mut self) -> usize { + let cum = self.x % 65536; + let s = if cum >= 32768 { 1 } else { 0 }; + self.x = 32768 * (self.x >> 16) + cum - 32768 * s as u64; + self.renorm(); + s + } + /// The canonical end: every word read, and the state `2^31`. + fn canonical(&self) -> bool { + !self.out && self.x == 1 << 31 && 4 * self.idx == self.s.len() + } +} + +/// E1's `strict(lo, hi)` decode of one symbol after its table step, from the text: the +/// escape's reads, then the checks of one symbol in their order. `n = 3`. +fn model_strict(m: &mut Model, s: usize, offset: i64, lo: i64, hi: i64, canonical: bool) -> Result { + let n2 = 1i64; + let (sym, count, last) = if (s as i64) < n2 { + (s as i64 + offset, 0u64, 1u64) + } else { + let count = m.bits(4); + let (mut raw, mut last) = (0u64, 0u64); + if count <= 8 { + for j in 0..count { + last = m.bits(4); + raw += last << (4 * j); + } + } + let value = if raw % 2 == 1 { -((raw / 2) as i64) - 1 } else { (raw / 2) as i64 + n2 }; + (value + offset, count, last) + }; + if canonical && m.out { + return Err(Code::StreamExhausted); + } + if (s as i64) == n2 && count > 8 { + return Err(Code::StreamNoncanonical); + } + if (s as i64) == n2 && count >= 1 && last == 0 { + return Err(Code::StreamNoncanonical); + } + if sym < lo || sym > hi { + return Err(Code::FieldRange); + } + Ok(sym) +} + +fn any_end() -> End { + if kani::any() { End::Canonical } else { End::FinalOnly } +} + +/// The expected outcome of a strict decode of `k` symbols against `[0, 2^15, 2^16]`. +fn model_strict_decode(stream: &[u8], k: usize, offset: i64, lo: i64, hi: i64, end: End) -> Result, StageRefusal> { + let mut m = Model::new(stream); + let mut out = Vec::new(); + for i in 0..k { + let s = m.half_table(); + match model_strict(&mut m, s, offset, lo, hi, end == End::Canonical) { + Ok(v) => out.push(v), + Err(code) => return Err(StageRefusal { code, at: i as i64 }), + } + } + match end { + End::Canonical if !m.canonical() => Err(StageRefusal { code: Code::StreamNoncanonical, at: k as i64 }), + End::FinalOnly if m.out => Err(StageRefusal { code: Code::StreamExhausted, at: k as i64 }), + _ => Ok(out), + } +} + +/// Whether two outcomes of a decode are the same, compared element by element (a +/// comparison of the vectors is a byte loop the checker would unroll). +fn same(a: &Result, StageRefusal>, b: &Result, StageRefusal>) -> bool { + match (a, b) { + (Ok(x), Ok(y)) => x.len() == y.len() && (0..x.len()).all(|i| x[i] == y[i]), + (Err(x), Err(y)) => x.code == y.code && x.at == y.at, + _ => false, + } +} + +// ------------------------------------------------------------------------------ K24 + +/// K24. `rans64_decode` under `strict(lo, hi)` (E1): it refuses `count > 8` and a +/// non-minimal encoding (`stream_noncanonical`), accepts minimal ones, and when several +/// refusals apply to one symbol it reports the first in E1's order — the run-out under +/// `canonical`, then `count > 8`, then the zero last group, then the range. The decode +/// equals the text's, written out above, symbol for symbol and refusal for refusal. +/// Window: every 64-byte stream, a 3-entry table (`[0, 2^15, 2^16]`), one or two +/// symbols, any offset and range within `i32`, both end rules. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(10)] +fn k24_rans64_strict_escape() { + let stream: [u8; 64] = kani::any(); + let k: usize = if kani::any() { 1 } else { 2 }; + let (offset, lo, hi): (i32, i32, i32) = (kani::any(), kani::any(), kani::any()); + kani::assume(lo <= hi); + let end = any_end(); + let t = Table { cdf: vec![0, 32768, 65536], offset: offset as i64 }; + let modes = Modes { table: TableRule::T4097, escape: Escape::Strict { lo, hi }, end }; + let got = rans64::decode(&stream, &[t], &vec![0; k], modes); + let want = model_strict_decode(&stream, k, offset as i64, lo as i64, hi as i64, end); + assert!(same(&got, &want), "the decode is the text's"); + kani::cover!(got.as_ref().is_err_and(|r| r.code == Code::StreamNoncanonical && r.at == 0), "a refused escape"); + kani::cover!(got.as_ref().is_ok_and(|v| v[0] != offset as i64), "an accepted escape"); +} + +// ------------------------------------------------------------------------------ K25 + +/// K25. The `canonical` end rule (E1, integer-payloads §2): a decode is accepted only +/// when, after its last symbol, the state is `2^31` and every word has been read, with +/// no run-out; otherwise it is refused, `stream_noncanonical` at the end. Window: every +/// 32-byte stream, the table `[0, 2^15, 2^16]`, one or two symbols, `strict` over all +/// of `i32`, so no symbol is refused for its range. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(10)] +fn k25_rans64_canonical_end() { + let stream: [u8; 32] = kani::any(); + let k: usize = if kani::any() { 1 } else { 2 }; + let t = Table { cdf: vec![0, 32768, 65536], offset: 0 }; + let modes = Modes { table: TableRule::T4097, escape: Escape::Strict { lo: i32::MIN, hi: i32::MAX }, end: End::Canonical }; + let got = rans64::decode(&stream, &[t], &vec![0; k], modes); + assert!(same(&got, &model_strict_decode(&stream, k, 0, i32::MIN as i64, i32::MAX as i64, End::Canonical))); + if got.is_ok() { + let mut m = Model::new(&stream); + for _ in 0..k { + let s = m.half_table(); + let _ = model_strict(&mut m, s, 0, i32::MIN as i64, i32::MAX as i64, true); + } + assert!(m.x == 1 << 31 && 4 * m.idx == stream.len() && !m.out, "accepted only at state 2^31 with every word read"); + } + kani::cover!(got.is_ok(), "a canonical stream"); +} + +// ------------------------------------------------------------------------------ K26 + +/// K26. `rans64_decode` under the `t2` table rule with `n = 2`, where every symbol is +/// the escape: total under both escape rules and both end rules — it returns its +/// symbols or a refusal, and never panics or overflows. Window: every 32-byte stream, +/// up to three symbols, any offset, any `strict` range. +#[kani::proof] +#[kani::unwind(12)] +fn k26_rans64_t2_is_total() { + let stream: [u8; 32] = kani::any(); + let k: usize = kani::any(); + kani::assume(k <= 3); + let offset: i32 = kani::any(); + let escape = if kani::any() { + Escape::Lenient + } else { + let (lo, hi): (i32, i32) = (kani::any(), kani::any()); + Escape::Strict { lo, hi } + }; + let empty = matches!(escape, Escape::Strict { lo, hi } if lo > hi); + let t = Table { cdf: vec![0, 65536], offset: offset as i64 }; + let modes = Modes { table: TableRule::T2, escape, end: any_end() }; + match rans64::decode(&stream, &[t], &vec![0; k], modes) { + Ok(v) => assert_eq!(v.len(), k), + Err(r) if r.at == -1 => assert!(empty && r.code == Code::ModelMismatch, "only an empty range is refused before any symbol"), + Err(r) => assert!(r.at >= 0 && r.at <= k as i64, "refused at a symbol or at the end"), + } +} + +// ------------------------------------------------------------------------------ K27 + +/// A fixed table of 256 entries (`nb·2^24 + base·2^16 + low`) whose fields take every +/// `nb` from 0 to 8, every base, and low bits `u·257`: the low byte is `u`, so `fac`'s +/// escape symbol 63 occurs, and as a 16-bit value it reaches 0 and −1, so `sgm`'s +/// escape (`sym + β = 0`) occurs for `β` of 0 and 1. Evaluated at compile time. +const fn fixed_table(seed: u32) -> [u32; 256] { + let mut t = [0u32; 256]; + let mut k = 0; + while k < 256 { + let u = k as u32; + t[k] = ((u + seed) % 9) << 24 | ((u * 37 + seed) % 256) << 16 | (u * 257); + k += 1; + } + t +} + +/// K27. `mans_decode` (E8) is total: for every stream, every bound `B_y` in +/// `[0, 255]`, every mask and every distribution index, a span of the latent decode +/// returns its symbols or refuses, and never panics; each new state is taken mod 2^8 +/// (the state is a byte). Window: 16-byte streams, two fixed tables (`fixed_table`), +/// spans of up to 5 positions. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(10)] +fn k27_mans_sgm_is_total() { + let stream: [u8; 16] = kani::any(); + let Ok(mut w) = Win::init(&stream) else { return }; + const TABLES: [[u32; 256]; 2] = [fixed_table(1), fixed_table(7)]; + let tables = TABLES; + let bounds: [i64; 2] = kani::any(); + kani::assume(bounds.iter().all(|b| (0..=255).contains(b))); + let n: usize = kani::any(); + kani::assume(n <= 5); + let mask: [bool; 5] = kani::any(); + let sigma: [usize; 5] = kani::any(); + kani::assume(sigma.iter().all(|&g| g < 2)); + let span = Span { mask: mask[..n].to_vec(), sigma: sigma[..n].to_vec() }; + if let Ok(v) = mans::sgm_span(&mut w, &tables, &bounds, &span, 0) { + assert_eq!(v.len(), n); + for (i, &x) in v.iter().enumerate() { + assert!((-32768..=32767).contains(&x), "every symbol is a wrap16 value"); + assert!(mask[i] || x == 0, "an unmasked position is 0"); + } + } +} + +/// K27. The hyper-latent decode (`fac`) of E8 is total: for every 16-byte stream, a +/// row of up to 5 symbols returns or refuses, and never panics. Window: a fixed row +/// table (`fixed_table`). +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(10)] +fn k27_mans_fac_is_total() { + let stream: [u8; 16] = kani::any(); + let Ok(mut w) = Win::init(&stream) else { return }; + const TZ: [u32; 256] = fixed_table(3); + let tz = TZ; + let n: usize = kani::any(); + kani::assume(n <= 5); + if let Ok(v) = mans::fac_row(&mut w, &tz, n, 0) { + assert_eq!(v.len(), n); + assert!(v.iter().all(|&x| (0..=255).contains(&x)), "every symbol is a byte"); + } +} + +/// K27. `decode_sgm` refuses a bound outside `[0, 255]` before any symbol: `B_y` is +/// unsigned (E8), so a bound read as signed can never reach a decode. +#[kani::proof] +#[kani::unwind(4)] +fn k27_mans_bounds_are_unsigned() { + let b: i64 = kani::any(); + kani::assume(!(0..=255).contains(&b)); + let pmf = vec![vec![256i64]]; + let r = mans::decode_sgm(&[0x80, 0, 0, 0, 0, 0, 0, 1], &pmf, &[b], &[]); + assert_eq!(r, Err(StageRefusal { code: Code::ModelMismatch, at: -1 }), "a bound outside [0, 255] is refused before any symbol"); +} + +// ------------------------------------------------------------------------------ K28 + +/// K28. The latent table build of E8, for any row that passes the load checks +/// (non-negative, summing to exactly 256): every slot is written, and `next ∈ [1, 511]`. +/// A slot no column writes would keep `next = 0`. Window: every row of width 8, every +/// entry symbolic; a narrower row builds the table its zero-extension to width 8 does +/// (the columns past its sum write nothing), so this covers every width up to 8. +#[cfg(kani_open)] +#[kani::proof] +#[kani::unwind(258)] +fn k28_mans_every_slot_written() { + let raw: [u16; 8] = kani::any(); + let row: [i64; 8] = [raw[0] as i64, raw[1] as i64, raw[2] as i64, raw[3] as i64, raw[4] as i64, raw[5] as i64, raw[6] as i64, raw[7] as i64]; + kani::assume(row.iter().all(|&p| p <= 256) && row.iter().sum::() == 256); + let (_, next) = mans::latent_slots(&row); + for &n in next.iter() { + assert!((1..=511).contains(&n), "every slot is written, with next ∈ [1, 511]"); + } +} + +/// K28. Each entry of a latent table, for every `next ∈ [1, 511]` (K28 above) and every +/// symbol: `nb ≤ 8`, `base = (next·2^nb) XOR 256 < 256`, and the three fields do not +/// overlap, so `nb`, `base` and `sym mod 2^16` read back from the entry. +#[kani::proof] +#[kani::unwind(11)] +fn k28_mans_entry_fields() { + let (sym, next): (i16, i64) = (kani::any(), kani::any()); + kani::assume((1..=511).contains(&next)); + let e = mans::latent_entry(sym as i64, next); + let nb = e >> 24; + assert!(nb <= 8, "nb ≤ 8"); + assert!(next << nb >= 256 && (nb == 0 || next << (nb - 1) < 256), "nb doublings bring next to 256 or more, and no fewer"); + assert_eq!((e >> 16) & 0xFF, ((next << nb) ^ 256) as u32, "base = (next·2^nb) XOR 256"); + assert!((((next << nb) ^ 256) as u32) < 256, "base < 256"); + assert_eq!(e & 0xFFFF, sym as u16 as u32, "sym mod 2^16"); +} + +// ------------------------------------------------------------------------------ K29 + +/// K29. `residual_step` (E9): its 32-bit form equals it, and every value that form +/// computes fits `i32` (each operation is checked), for every `r` in `i32`, every +/// `q ∈ [1, 65535]`, every `pred ∈ [lo, hi]`, and every range on which the form is +/// stated (`hi − lo ≤ 65535`, with `lo − 131070` and `hi + 131070` in `i32`): the +/// registered `U8` and `I16` ranges among them. +#[kani::proof] +fn k29_residual_step_32bit_identity_every_range() { + let (lo, hi): (i32, i32) = (kani::any(), kani::any()); + kani::assume(i32_form_fits(lo, hi)); + let (pred, r, q): (i32, i32, i32) = (kani::any(), kani::any(), kani::any()); + kani::assume(lo <= pred && pred <= hi && (1..=65535).contains(&q)); + let exact = residual_step(pred as i64, r as i64, q as i64, lo as i64, hi as i64).expect("in E9's domain"); + assert_eq!(residual_step_i32(pred, r, q, lo, hi) as i64, exact, "the 32-bit form is E9"); + kani::cover!(lo == 0 && hi == 255, "U8"); + kani::cover!(lo == -32768 && hi == 32767, "I16"); +} + +fn residual_case(lo: i32, hi: i32) { + let (pred, r, q): (i32, i32, i32) = (kani::any(), kani::any(), kani::any()); + kani::assume(lo <= pred && pred <= hi && (1..=65535).contains(&q)); + let exact = residual_step(pred as i64, r as i64, q as i64, lo as i64, hi as i64).expect("in E9's domain"); + assert_eq!(residual_step_i32(pred, r, q, lo, hi) as i64, exact, "the 32-bit form is E9"); +} + +/// K29 on the registered ranges, `U8 = [0, 255]` and `I16 = [−32768, 32767]`: the +/// 32-bit form equals E9 and every value it computes fits `i32`, for every `r` in +/// `i32`, every `q ∈ [1, 65535]` and every `pred` in the range. +#[kani::proof] +fn k29_residual_step_32bit_identity_registered_ranges() { + if kani::any() { residual_case(0, 255) } else { residual_case(-32768, 32767) } +} + +// ------------------------------------------------------------------------------ K30 + +/// K30. E5 `scale_index` lies in `[0, n − 1]` for every `v` in `i64`, every shift in +/// `0..=127` and every `n ≥ 1`. +#[kani::proof] +fn k30_scale_index_in_range() { + let (v, s, n): (i64, u32, i64) = (kani::any(), kani::any(), kani::any()); + kani::assume(s <= 127 && n >= 1); + let i = scale_index(v, s, n).expect("defined for n ≥ 1 and s ≤ 127"); + assert!(0 <= i && i < n); +} + +fn block_case(h: u32, w: u32, b: u32) { + let raw: [i32; 9] = kani::any(); + let data: Vec = raw[..(h * w) as usize].iter().map(|&v| v as i64).collect(); + let (s, lo, hi): (u32, i64, i64) = (kani::any(), kani::any(), kani::any()); + kani::assume(s <= 127 && lo <= hi); + let out = block_stat(&Tensor::new(1, h, w, data), b, s, lo, hi).expect("b ≥ 1, s ≤ 127, lo ≤ hi"); + let (y, x): (u32, u32) = (kani::any(), kani::any()); + kani::assume(y < h && x < w); + let v = out.data[(y * w + x) as usize]; + assert!(lo <= v && v <= hi); + let (y0, x0) = ((y / b) * b, (x / b) * b); + assert_eq!(v, out.data[(y0 * w + x0) as usize], "a block shares one value"); +} + +/// K30. E6 `block_stat`: every output lies in `[lo, hi]`, and every position of a block +/// takes its block's value. Window: the shapes below — full blocks, partial last +/// blocks in either direction, and blocks of 1 — with one channel, any shift in +/// `0..=127`, any range and any `i32` inputs. +#[kani::proof] +#[kani::unwind(11)] +fn k30_block_stat_in_range() { + match kani::any::() % 4 { + 0 => block_case(3, 3, 2), + 1 => block_case(3, 2, 3), + 2 => block_case(2, 3, 1), + _ => block_case(1, 1, 1), + } +} + +/// K30. E7 `band_lookup`: for up to 3 edges and any `v`, the band is `#{k : v ≥ e_k}` +/// and the result is that entry of the row; a row of the wrong length, or a row index +/// past the table, is refused rather than read out of range. +#[kani::proof] +#[kani::unwind(6)] +fn k30_band_lookup_in_range() { + let m: usize = kani::any(); + kani::assume(m <= 3); + let e: [i64; 3] = kani::any(); + let v: i64 = kani::any(); + let row_len: usize = kani::any(); + kani::assume(row_len <= 4); + let cells: [i64; 4] = kani::any(); + let table = vec![cells[..row_len].to_vec()]; + let row: usize = kani::any(); + kani::assume(row <= 1); + let band = e[..m].iter().filter(|&&x| v >= x).count(); + match band_lookup(v, &e[..m], &table, row) { + Some(r) => assert!(row == 0 && row_len == m + 1 && r == cells[band]), + None => assert!(row == 1 || row_len != m + 1), + } +} diff --git a/wai/wai-ops/src/stage/mans.rs b/wai/wai-ops/src/stage/mans.rs index 3c7394217..0a53105fa 100644 --- a/wai/wai-ops/src/stage/mans.rs +++ b/wai/wai-ops/src/stage/mans.rs @@ -9,7 +9,7 @@ use crate::code::Code; use crate::stage::rans64::StageRefusal; /// The window and the two states. -struct Win { +pub(crate) struct Win { m: Vec, p: usize, h: u64, @@ -22,7 +22,7 @@ struct Win { pos: i64, } -type R = Result; +pub(crate) type R = Result; impl Win { fn le64(&self, i: usize) -> u64 { @@ -30,7 +30,7 @@ impl Win { b.copy_from_slice(&self.m[i..i + 8]); u64::from_le_bytes(b) } - fn init(stream: &[u8]) -> R { + pub(crate) fn init(stream: &[u8]) -> R { let mut m = vec![0u8; 8]; m.extend_from_slice(stream); let mut w = Win { m, p: stream.len(), h: 0, b: 0, s: [0, 0], pos: 0 }; @@ -90,43 +90,61 @@ pub fn build_latent_tables(pmf: &[Vec]) -> Option> { if row.len() != w || row.iter().any(|&p| p < 0) || row.iter().sum::() != 256 { return None; } - let mut c = vec![0i64; w + 1]; - for k in 0..w { - c[k + 1] = c[k] + row[k]; - } - let f = |k: usize| c[k] - c[k] / 2; - let g = |k: usize| c[k] / 2 + 128; - let sym = |k: usize| -> i64 { if k % 2 == 0 { (k / 2) as i64 } else { -(((k + 1) / 2) as i64) } }; - let mut symbols = [0i64; 256]; - let mut next = [0i64; 256]; - let mut k = 0; - while c[k] < 256 { - for u in f(k)..f(k + 1) { - symbols[u as usize] = sym(k); - next[u as usize] = row[k] + (u - f(k)); - } - for u in g(k)..g(k + 1) { - symbols[u as usize] = sym(k); - next[u as usize] = row[k] + (f(k + 1) - f(k)) + (u - g(k)); - } - k += 1; - } + let (symbols, next) = latent_slots(row); let mut t = [0u32; 256]; for u in 0..256 { - // Every slot is written and next ∈ [1, 511], so nb ≤ 8; the bound only keeps - // the loop total. - let mut nb = 0u32; - while nb < 9 && next[u] << nb < 256 { - nb += 1; - } - let base = ((next[u] << nb) ^ 256) as u32; - t[u] = (nb << 24) | (base << 16) | (symbols[u].rem_euclid(65536) as u32); + t[u] = latent_entry(symbols[u], next[u]); } out.push(t); } Some(out) } +/// Each slot's symbol and `next` for one row that passed the load checks (§5E E8, +/// *Building the latent tables*). A slot no column writes keeps `next = 0`. +pub(crate) fn latent_slots(row: &[i64]) -> ([i64; 256], [i64; 256]) { + let w = row.len(); + let mut c = vec![0i64; w + 1]; + for k in 0..w { + c[k + 1] = c[k] + row[k]; + } + let f = |k: usize| c[k] - c[k] / 2; + let g = |k: usize| c[k] / 2 + 128; + let sym = |k: usize| -> i64 { if k % 2 == 0 { (k / 2) as i64 } else { -(((k + 1) / 2) as i64) } }; + let mut symbols = [0i64; 256]; + let mut next = [0i64; 256]; + // Each column k, while C[k] < 256, writes the slots of [F[k], F[k+1]) and + // [G[k], G[k+1]). Every slot is visited by its index, so each loop has a fixed + // bound. + for k in 0..w { + if c[k] >= 256 { + break; + } + for u in 0..256i64 { + if f(k) <= u && u < f(k + 1) { + symbols[u as usize] = sym(k); + next[u as usize] = row[k] + (u - f(k)); + } + if g(k) <= u && u < g(k + 1) { + symbols[u as usize] = sym(k); + next[u as usize] = row[k] + (f(k + 1) - f(k)) + (u - g(k)); + } + } + } + (symbols, next) +} + +/// A slot's entry: `nb·2^24 + base·2^16 + (sym mod 2^16)`. Every slot is written and +/// `next ∈ [1, 511]`, so `nb ≤ 8`; the bound on the loop only keeps it total. +pub(crate) fn latent_entry(sym: i64, next: i64) -> u32 { + let mut nb = 0u32; + while nb < 9 && next << nb < 256 { + nb += 1; + } + let base = ((next << nb) ^ 256) as u32; + (nb << 24) | (base << 16) | (sym.rem_euclid(65536) as u32) +} + /// One `sgm` span: the masked positions and their distributions. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Span { @@ -138,10 +156,10 @@ pub struct Span { /// and the spans, decoded in order from one window. Returns one array per span. pub fn decode_sgm(stream: &[u8], pmf: &[Vec], bounds: &[i64], spans: &[Span]) -> Result>, StageRefusal> { let before = StageRefusal { code: Code::ModelMismatch, at: -1 }; - let tables = build_latent_tables(pmf).ok_or(before)?; if bounds.iter().any(|&b| !(0..=255).contains(&b)) { return Err(before); } + let tables = build_latent_tables(pmf).ok_or(before)?; let nd = tables.len().min(bounds.len()); for s in spans { if s.mask.len() != s.sigma.len() || s.sigma.iter().any(|&g| g >= nd) { @@ -162,7 +180,7 @@ pub fn decode_sgm(stream: &[u8], pmf: &[Vec], bounds: &[i64], spans: &[Span Ok(out) } -fn sgm_span(w: &mut Win, t: &[[u32; 256]], bounds: &[i64], s: &Span, base: i64) -> R> { +pub(crate) fn sgm_span(w: &mut Win, t: &[[u32; 256]], bounds: &[i64], s: &Span, base: i64) -> R> { let n = s.mask.len(); let mut sym = vec![0i64; n]; let inb = |w: &mut Win, which: usize, i: usize, sym: &mut [i64]| -> R<()> { @@ -266,7 +284,7 @@ pub fn decode_fac(stream: &[u8], rows: &[Vec], lengths: &[usize]) -> Result Ok(out) } -fn fac_row(w: &mut Win, tz: &[u32; 256], n: usize, base: i64) -> R> { +pub(crate) fn fac_row(w: &mut Win, tz: &[u32; 256], n: usize, base: i64) -> R> { let mut sym = vec![0i64; n]; let inb = |w: &mut Win, which: usize, i: usize, sym: &mut [i64]| -> R<()> { w.pos = base + i as i64; diff --git a/wai/wai-ops/src/vectors.rs b/wai/wai-ops/src/vectors.rs index 89eb15ca2..5485e851a 100644 --- a/wai/wai-ops/src/vectors.rs +++ b/wai/wai-ops/src/vectors.rs @@ -9,6 +9,7 @@ use alloc::string::{String, ToString}; use alloc::vec; use alloc::vec::Vec; +use crate::bounds::Profile; use crate::code::Code; use crate::graph; use crate::interp::{self, Sequence, Tensor}; @@ -66,17 +67,21 @@ pub fn tensor_c(t: &Tensor) -> C { ]) } -/// Recompute one graph vector (§14.1): `load`, and every decode's `expect`. +/// Recompute one graph vector (§14.1): `load` (steps 1–8), `profiles` and every +/// decode's `expect`. A graph that loads lists exactly the profiles its verdict +/// meets, and its decodes run; one whose load is refused lists both profiles, since +/// an implementation of either refuses it, and has no decodes. The `profiles` a line +/// carries are not read: they are recomputed. pub fn graph_line(v: &Value) -> Result { let hexg = get(v, "graph")?.as_str().ok_or("graph is not a string")?; let bytes = unhex(hexg).ok_or("graph is not lowercase hexadecimal")?; let id = get(v, "id")?.as_str().ok_or("id is not a string")?; - let profiles = arr(v, "profiles")?; + arr(v, "profiles")?; let decodes = arr(v, "decodes")?; - let loaded = graph::load(&bytes); - let load = match &loaded { - Ok(_) => C::s("ok"), - Err(r) => C::s(r.code.as_str()), + let loaded = graph::load(&bytes, Profile::Acc64); + let (load, profiles) = match &loaded { + Ok(g) => (C::s("ok"), Profile::ALL.iter().filter(|p| g.meets(**p)).map(|p| C::s(p.as_str())).collect()), + Err(r) => (C::s(r.code.as_str()), Profile::ALL.iter().map(|p| C::s(p.as_str())).collect()), }; let mut out = Vec::new(); if let Ok(g) = &loaded { @@ -100,7 +105,7 @@ pub fn graph_line(v: &Value) -> Result { ("graph", C::Str(hex(&bytes))), ("id", C::s(id)), ("load", load), - ("profiles", C::Arr(profiles.iter().map(|p| C::s(p.as_str().unwrap_or("?"))).collect())), + ("profiles", C::Arr(profiles)), ])) } diff --git a/wai/wai-ops/src/xint.rs b/wai/wai-ops/src/xint.rs index 53fc45721..a789f6095 100644 --- a/wai/wai-ops/src/xint.rs +++ b/wai/wai-ops/src/xint.rs @@ -17,9 +17,18 @@ use core::cmp::Ordering; const N: usize = 8; -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, Eq, Hash, Debug)] pub struct I512([u64; N]); +/// Limb by limb, written out: the derived comparison of the array is a byte loop, +/// which a model checker must unwind 64 times at every use. +impl PartialEq for I512 { + fn eq(&self, o: &I512) -> bool { + let (a, b) = (&self.0, &o.0); + a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3] && a[4] == b[4] && a[5] == b[5] && a[6] == b[6] && a[7] == b[7] + } +} + impl Default for I512 { fn default() -> Self { I512::ZERO @@ -44,6 +53,12 @@ impl I512 { pub const fn from_u64(v: u64) -> I512 { I512::from_u128(v as u128) } + /// The value whose eight little-endian 64-bit limbs are `l`: a symbolic value for + /// the model checker. + #[cfg(kani)] + pub(crate) const fn from_limbs(l: [u64; N]) -> I512 { + I512(l) + } pub fn is_neg(&self) -> bool { self.0[N - 1] >> 63 == 1 @@ -51,6 +66,10 @@ impl I512 { pub fn is_zero(&self) -> bool { self.0.iter().all(|&l| l == 0) } + /// Whether the value is odd (`v mod 2 = 1`), negative values included. + pub fn is_odd(&self) -> bool { + self.0[0] & 1 == 1 + } fn not(self) -> I512 { let mut r = self.0; diff --git a/wai/wai-ops/tests/goldens.rs b/wai/wai-ops/tests/goldens.rs index c342762ca..cb42fc898 100644 --- a/wai/wai-ops/tests/goldens.rs +++ b/wai/wai-ops/tests/goldens.rs @@ -5,15 +5,14 @@ //! what a capability's driver does around its graphs (§13.5). They check the lowerings //! and the operators against outputs that were fixed before either existed. //! -//! Every graph a driver runs goes through `graph::load` of its bytes, as a sink's -//! does. That is why these tests need the `uncertified` switch: until the certifier -//! exists, load step 8 refuses every graph without it. -#![cfg(feature = "uncertified")] +//! Every graph a driver runs goes through `graph::load` of its bytes under `acc64`, +//! the profile every lowering of §13 declares, as a sink's does: load step 8 runs the +//! bounds pass and refuses a set whose certificate does not meet it. use std::path::{Path, PathBuf}; -use wai_ops::graph; -use wai_ops::interp::{Sequence, Tensor, run}; +use wai_ops::{Profile, bounds, graph, plan}; +use wai_ops::interp::{Sequence, Tensor, run_observed}; use wai_ops::json::{self, Value, hex}; use wai_ops::lower; use wai_ops::sha256::sha256; @@ -42,10 +41,19 @@ fn hwc(t: &Tensor) -> Vec { o } /// One decode of a lowered graph with one data input: loaded from its bytes, as a sink -/// loads it, then run. +/// loads it, then run, observed: every value each operator forms under a named +/// intermediate (§8.5, Table 8.5-A), and every producer result, must lie in the interval +/// the graph's bounds pass records for it. fn one(g: &wai_ops::Graph, x: Tensor, sc: &[i64]) -> Tensor { - let g = graph::load(&g.to_bytes()).expect("a lowered graph loads"); - run(&g, &[x], sc, &mut Sequence::new()).unwrap().remove(0) + let g = graph::load(&g.to_bytes(), Profile::Acc64).expect("a lowered graph loads"); + let sizes = plan::load_plan(&g).unwrap(); + let b = bounds::pass(&g, sizes.as_deref()).unwrap(); + let mut w = bounds::Within::new(&b); + let out = run_observed(&g, &[x], sc, &mut Sequence::new(), &mut w).unwrap().remove(0); + assert!(w.outside.is_empty(), "values outside their certified intervals: {:?}", w.outside); + assert!(w.unrecorded.is_empty(), "values under keys the certificate does not record: {:?}", w.unrecorded); + assert!(w.seen > 0); + out } fn u32le(b: &[u8], o: usize) -> u32 { u32::from_le_bytes(b[o..o + 4].try_into().unwrap()) diff --git a/wai/wai-ops/tests/step8.rs b/wai/wai-ops/tests/step8.rs index 378c818e1..4943a4685 100644 --- a/wai/wai-ops/tests/step8.rs +++ b/wai/wai-ops/tests/step8.rs @@ -1,33 +1,61 @@ -//! Without the `uncertified` switch, which only the tests, the conformance tool and -//! its browser-engine build enable, load step 8 refuses every graph (§10.5): until the -//! certifier exists, the default build decodes nothing. The interpreter takes only a -//! `Loaded` graph, which only `graph::load` makes, so a lowered set's graphs cannot be -//! run around that refusal. (That `run` rejects a `Graph` at compile time is the -//! `compile_fail` example on `Loaded`.) +//! Load step 8 (§10.5): every graph loads under a profile, and loads only when its +//! verdict meets that profile (§8.6). The interpreter takes only a `Loaded` graph, +//! which only `graph::load` makes, so a lowered set's graphs cannot be run around +//! the verdict. (That `run` rejects a `Graph` at compile time is the `compile_fail` +//! example on `Loaded`.) use std::path::PathBuf; use wai_ops::code::{Code, Refusal, Site}; -use wai_ops::{graph, lower}; +use wai_ops::{Profile, graph, lower}; fn read(p: &str) -> Vec { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..").join(p); std::fs::read(&path).unwrap_or_else(|e| panic!("{p}: {e}")) } -/// Every lowered graph of the committed int_synth sets loads through steps 1–7, and -/// then step 8 refuses it in the default build and passes it with the switch. +fn step8() -> Refusal { + Refusal::new(Code::ModelMismatch, Site::Load(8)) +} + +/// Every lowered graph of the committed int_synth sets loads under `acc64`. The +/// facade, gradient and bloom sets also load under `acc32`; photo does not, and its +/// `acc32` load is refused at step 8. #[test] -fn a_lowered_set_decodes_only_through_load_step_8() { - for name in ["gradient", "bloom", "facade", "photo"] { +fn a_lowered_set_loads_only_under_a_profile_its_verdict_meets() { + for (name, acc32) in [("gradient", true), ("bloom", true), ("facade", true), ("photo", false)] { let set = lower::int_synth(&read(&format!("neural-conformance/vectors/{name}/int_synth.json"))).unwrap(); for (role, g) in &set.roles { - let r = graph::load(&g.to_bytes()); - if cfg!(feature = "uncertified") { - assert!(r.is_ok(), "{name}/{role}"); - } else { - assert_eq!(r.unwrap_err(), Refusal::new(Code::ModelMismatch, Site::Load(8)), "{name}/{role}"); + let b = g.to_bytes(); + let l = graph::load(&b, Profile::Acc64).unwrap_or_else(|e| panic!("{name}/{role}: {e:?}")); + assert_eq!(l.meets(Profile::Acc32), acc32, "{name}/{role}"); + match graph::load(&b, Profile::Acc32) { + Ok(_) => assert!(acc32, "{name}/{role} loads under acc32"), + Err(e) => { + assert!(!acc32, "{name}/{role} is refused under acc32"); + assert_eq!(e, step8(), "{name}/{role}"); + } } } } } + +/// The overflow set of §14.3, whose accumulator passes i64 by one unit, is refused at +/// step 8 under both profiles, and so is the same set one unit inside. +#[test] +fn the_overflow_set_is_refused_at_step_8() { + let set = lower::int_synth(&read("ops-conformance/sets/overflow_acc64/int_synth.json")).unwrap(); + let b = set.get("synth").unwrap().to_bytes(); + for p in Profile::ALL { + assert_eq!(graph::load(&b, p).unwrap_err(), step8(), "{p:?}"); + } +} + +/// The set of §14.3 whose pin claims `acc32` meets `acc64` and fails `acc32`. +#[test] +fn the_acc32_claim_set_loads_under_acc64_only() { + let set = lower::int_synth(&read("ops-conformance/sets/claim_acc32/int_synth.json")).unwrap(); + let b = set.get("synth").unwrap().to_bytes(); + assert!(!graph::load(&b, Profile::Acc64).unwrap().meets(Profile::Acc32)); + assert_eq!(graph::load(&b, Profile::Acc32).unwrap_err(), step8()); +} diff --git a/wai/wai-ops/tests/trace.rs b/wai/wai-ops/tests/trace.rs new file mode 100644 index 000000000..e0994d3b1 --- /dev/null +++ b/wai/wai-ops/tests/trace.rs @@ -0,0 +1,151 @@ +//! Hand-built graphs at the edge of what `acc64` certifies, run observed: every value +//! each operator forms under a named intermediate (§8.5, Table 8.5-A), and every +//! producer result, lies in the interval the bounds pass records for it. +//! +//! Each graph loads from its bytes under `acc64` (load step 8 included), and is run on +//! inputs at the ends of their declared ranges — all at one end, all at the other, the +//! two ends alternating in both phases — and on pseudo-random inputs within them. + +use wai_ops::bounds::{self, Within}; +use wai_ops::graph::{self, BiasKind, CAP, Graph, InputRec, Op, Params, Round, Rq, ScalarRec, TensorRec, opcode::*}; +use wai_ops::interp::{Sequence, Tensor, run_observed}; +use wai_ops::{Profile, plan}; + +fn rng(s: &mut u64) -> u64 { + *s = s.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + *s >> 11 +} + +/// A one-operator graph: inputs with records `ins` (declared sizes `hw`, or none), one +/// output. +fn graph1(ins: Vec, out: TensorRec, code: u8, p: Params, scalars: Vec, hw: (u32, u32)) -> Graph { + let n = ins.len() as u32; + let mut tensors = ins; + tensors.push(out); + Graph { + max_elems: CAP as u32, + scalars, + inputs: (0..n).map(|t| InputRec { tensor: t, max_h: hw.0, max_w: hw.1, kind: 0, src: 0, init: 0 }).collect(), + outputs: vec![n], + tensors, + ops: vec![Op { code, ins: (0..n).collect(), outs: vec![n], p }], + } +} + +/// Inputs for one run: pattern 0 all at `lo`, 1 all at `hi`, 2 and 3 alternating, and +/// above 3 pseudo-random within `[lo, hi]`. +fn fill(c: u32, h: u32, w: u32, lo: i64, hi: i64, pattern: u32, s: &mut u64) -> Tensor { + let n = (c * h * w) as usize; + let data = (0..n) + .map(|k| match pattern { + 0 => lo, + 1 => hi, + 2 => if k % 2 == 0 { lo } else { hi }, + 3 => if k % 2 == 0 { hi } else { lo }, + _ => { + let span = (hi as i128 - lo as i128) as u128 + 1; + (lo as i128 + (rng(s) as u128 % span) as i128) as i64 + } + }) + .collect(); + Tensor::new(c, h, w, data) +} + +/// Load `g` under `acc64`, then run it on every pattern for its inputs' records and +/// `shapes`, observed; every value must lie in its interval. +fn check(name: &str, g: Graph, shapes: &[(u32, u32)], scalars: &[i64]) { + let l = graph::load(&g.to_bytes(), Profile::Acc64).unwrap_or_else(|r| panic!("{name}: refused at load: {r:?}")); + let sizes = plan::load_plan(&l).unwrap(); + let b = bounds::pass(&l, sizes.as_deref()).unwrap(); + let mut s = 0x9E3779B97F4A7C15u64; + let mut seen = 0u64; + for pattern in 0..12 { + let inputs: Vec = l.inputs.iter().zip(shapes).map(|(i, &(h, w))| { + let t = &l.tensors[i.tensor as usize]; + fill(t.channels, h, w, t.lo, t.hi, pattern, &mut s) + }).collect(); + let mut obs = Within::new(&b); + run_observed(&l, &inputs, scalars, &mut Sequence::new(), &mut obs).unwrap_or_else(|r| panic!("{name}: pattern {pattern} refused: {r:?}")); + assert!(obs.outside.is_empty(), "{name}: pattern {pattern}: outside: {:?}", obs.outside); + assert!(obs.unrecorded.is_empty(), "{name}: pattern {pattern}: unrecorded: {:?}", obs.unrecorded); + seen += obs.seen; + } + assert!(seen > 0, "{name}"); +} + +fn rq(round: Round, bias: BiasKind, b: Vec, m: Option>, shift: u8) -> Rq { + let (m_kind, m_bytes, mult) = match m { + None => (0, 0, vec![]), + Some(v) => (2, 8, v), + }; + let b_bytes = if bias == BiasKind::None { 0 } else { 8 }; + Rq { round, bias_kind: bias, m_kind, s_kind: 1, m_bytes, b_bytes, mult, shift: vec![shift], bias: if bias == BiasKind::None { vec![] } else { b } } +} + +#[test] +fn convolutions_at_the_edge() { + // 18 terms of 2^20 × 2^38: 2^62.2, under i64; products by ±2^30, under i128. + let w: Vec = (0..36).map(|k| if k % 3 == 0 { -(1 << 20) } else { 1 << 20 }).collect(); + for round in [Round::Floor, Round::HalfUp, Round::HalfEven] { + let r = rq(round, BiasKind::Post, vec![i32::MAX as i64, i32::MIN as i64], Some(vec![1 << 30, -(1 << 30)]), 40); + let p = Params::Conv { cout: 2, kh: 3, kw: 3, sh: 1, sw: 1, ph: 1, pw: 1, groups: 1, w_bytes: 4, rq: r, w: w.clone() }; + check("conv", graph1(vec![TensorRec::check(2, -(1 << 38), 1 << 38)], TensorRec::derived(2), CONV, p, vec![], (0, 0)), &[(4, 5)], &[]); + let r = rq(round, BiasKind::Pre, vec![-(1 << 61), 1 << 61], None, 63); + let p = Params::ConvT { cout: 2, kh: 3, kw: 3, sh: 2, sw: 2, ph: 1, pw: 1, oph: 1, opw: 1, w_bytes: 4, rq: r, w: w.clone() }; + check("conv_transpose", graph1(vec![TensorRec::check(2, -(1 << 38), 1 << 38)], TensorRec::derived(2), CONV_TRANSPOSE, p, vec![], (0, 0)), &[(3, 4)], &[]); + } +} + +#[test] +fn requantisations_and_products_at_the_edge() { + let r = rq(Round::HalfUp, BiasKind::Pre, vec![i64::MIN / 2, i64::MAX / 2], Some(vec![i64::MAX, i64::MIN]), 127); + check("rescale", graph1(vec![TensorRec::check(2, i64::MIN / 2, i64::MAX / 2)], TensorRec::derived(2), RESCALE, Params::Rescale(r), vec![], (0, 0)), &[(2, 3)], &[]); + let p = Params::Chscale { scalar: 0, n_rows: 2, round: Round::HalfEven, m_bytes: 8, shift: 64, m: vec![i64::MAX, i64::MIN, -1, 1] }; + check("chscale", graph1(vec![TensorRec::check(2, i64::MIN, i64::MAX)], TensorRec::derived(2), CHSCALE, p.clone(), vec![ScalarRec { lo: 0, hi: 1 }], (0, 0)), &[(2, 2)], &[0]); + check("chscale", graph1(vec![TensorRec::check(2, i64::MIN, i64::MAX)], TensorRec::derived(2), CHSCALE, p, vec![ScalarRec { lo: 0, hi: 1 }], (0, 0)), &[(2, 2)], &[1]); + let r = rq(Round::Floor, BiasKind::None, vec![], Some(vec![1 << 40, -(1 << 40)]), 70); + check("mul", graph1(vec![TensorRec::check(2, -(1 << 31), 1 << 31), TensorRec::check(1, i32::MIN as i64, i32::MAX as i64)], TensorRec::derived(2), MUL, Params::Mul(r), vec![], (0, 0)), &[(2, 2), (2, 2)], &[]); + let gr = Rq { round: Round::HalfUp, bias_kind: BiasKind::None, m_kind: 0, s_kind: 1, m_bytes: 0, b_bytes: 0, mult: vec![], shift: vec![16], bias: vec![] }; + check("gram", graph1(vec![TensorRec::check(4, -(1 << 28), 1 << 28), TensorRec::check(4, -(1 << 28), 1 << 28)], TensorRec::derived(4), GRAM, Params::Gram { groups: 2, rq: gr.clone() }, vec![], (3, 3)), &[(3, 3), (3, 3)], &[]); + check("apply", graph1(vec![TensorRec::check(4, -(1 << 30), 1 << 30), TensorRec::check(4, -(1 << 31), 1 << 31)], TensorRec::derived(4), APPLY, Params::Apply { groups: 2, rq: gr }, vec![], (0, 0)), &[(1, 2), (3, 3)], &[]); +} + +#[test] +fn elementwise_at_the_edge() { + check("leaky", graph1(vec![TensorRec::check(1, -(1 << 31), i64::MAX)], TensorRec::derived(1), LEAKY, Params::Leaky { a: 1 << 31, f: 63 }, vec![], (0, 0)), &[(3, 3)], &[]); + check("leaky", graph1(vec![TensorRec::check(1, i32::MIN as i64, 5)], TensorRec::derived(1), LEAKY, Params::Leaky { a: i32::MIN as i64, f: 0 }, vec![], (0, 0)), &[(3, 3)], &[]); + let mut t = vec![0i16; 65536]; + for (k, v) in t.iter_mut().enumerate().skip(1) { + *v = ((k as i64 * 7919) % 65536 - 32768) as i16; + } + check("lut16", graph1(vec![TensorRec::check(1, -32767, 32767)], TensorRec::derived(1), LUT16, Params::Lut16 { e_in: -128, e_out: -128, t }, vec![], (0, 0)), &[(4, 4)], &[]); + check("abs", graph1(vec![TensorRec::check(1, i64::MIN + 1, i64::MAX)], TensorRec::derived(1), ABS, Params::None, vec![], (0, 0)), &[(2, 2)], &[]); + check("chunk_add", graph1(vec![TensorRec::check(2, i64::MIN / 2, i64::MAX / 2)], TensorRec::derived(1), CHUNK_ADD, Params::None, vec![], (0, 0)), &[(2, 2)], &[]); +} + +#[test] +fn normalisations_and_scalar_functions_at_the_edge() { + // igdn: γ·x² of 2^31 × 2^62 = 2^93, under i128; r of the final norm under 2^47. + let p = Params::Igdn { gf: 0, frac: 30, g_bytes: 4, gamma: vec![i32::MAX as i64, -1, 7, i32::MIN as i64], beta: vec![i64::MAX, i64::MIN] }; + check("igdn", graph1(vec![TensorRec::check(2, -(1 << 31), 1 << 31)], TensorRec::derived(2), IGDN, p, vec![], (0, 0)), &[(2, 3)], &[]); + for eps in [1u64, 1 << 32, u64::MAX] { + let p = Params::LayerNorm { eps, g_bytes: 8, gamma: vec![i32::MAX as i64, i32::MIN as i64, 1], beta: vec![i64::MAX / 4, i64::MIN / 4, 0] }; + check("layernorm_c", graph1(vec![TensorRec::check(3, -(1 << 40), 1 << 40)], TensorRec::derived(3), LAYERNORM_C, p, vec![], (0, 0)), &[(2, 2)], &[]); + check("l2norm", graph1(vec![TensorRec::check(2, -(1 << 40), 1 << 40)], TensorRec::derived(2), L2NORM, Params::L2norm { eps }, vec![], (3, 3)), &[(3, 3)], &[]); + } + // The widest spread acc64 allows: exp.negx = h − l = 2^63 − 1. One more, and the + // set is refused at load (below). + check("softmax", graph1(vec![TensorRec::check(2, -(1 << 62), (1 << 62) - 1)], TensorRec::derived(2), SOFTMAX, Params::None, vec![], (2, 5)), &[(2, 5)], &[]); + let wide = graph1(vec![TensorRec::check(2, -(1 << 62), 1 << 62)], TensorRec::derived(2), SOFTMAX, Params::None, vec![], (2, 5)); + assert!(graph::load(&wide.to_bytes(), Profile::Acc64).is_err(), "exp.negx = 2^63 does not fit i64"); + check("softmax", graph1(vec![TensorRec::check(1, -5, 7)], TensorRec::derived(1), SOFTMAX, Params::None, vec![], (1, 4)), &[(1, 4)], &[]); + check("sigmoid", graph1(vec![TensorRec::check(1, i64::MIN + 1, i64::MAX)], TensorRec::derived(1), SIGMOID, Params::None, vec![], (0, 0)), &[(3, 3)], &[]); + check("sigmoid", graph1(vec![TensorRec::check(1, -200000, 200000)], TensorRec::derived(1), SIGMOID, Params::None, vec![], (0, 0)), &[(3, 3)], &[]); + // α = −2^63 gives ⌊α·(−2^16) / 2^16⌋ = 2^63, past i64: refused at load. + let wide = graph1(vec![TensorRec::check(1, -1, 0)], TensorRec::derived(1), ELU, Params::Elu { alpha: i64::MIN }, vec![], (0, 0)); + assert!(graph::load(&wide.to_bytes(), Profile::Acc64).is_err(), "elu's producer result reaches 2^63"); + for alpha in [i64::MAX, i64::MIN + 1, 65536, -3] { + check("elu", graph1(vec![TensorRec::check(1, i64::MIN + 1, i64::MAX)], TensorRec::derived(1), ELU, Params::Elu { alpha }, vec![], (0, 0)), &[(3, 3)], &[]); + check("elu", graph1(vec![TensorRec::check(1, -300000, 10)], TensorRec::derived(1), ELU, Params::Elu { alpha }, vec![], (0, 0)), &[(3, 3)], &[]); + } +} diff --git a/wai/wai-ops/tests/verdicts.rs b/wai/wai-ops/tests/verdicts.rs new file mode 100644 index 000000000..a3e74a75d --- /dev/null +++ b/wai/wai-ops/tests/verdicts.rs @@ -0,0 +1,78 @@ +//! The vectors whose outcome only load step 8 decides (§14.1 item 6), checked against +//! the reason the text gives for each: the bounds pass must refuse or tag them for +//! that reason, not another. + +use std::path::PathBuf; + +use wai_ops::bounds::{self, Profile}; +use wai_ops::json::{self, unhex}; +use wai_ops::{graph::Graph, plan}; + +fn lines(file: &str) -> Vec { + let p = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../ops-conformance").join(file); + std::fs::read_to_string(&p).unwrap().lines().map(|l| json::parse(l.as_bytes()).unwrap()).collect() +} + +fn graph_of(v: &json::Value) -> Graph { + Graph::parse(&unhex(v.get("graph").unwrap().as_str().unwrap()).unwrap()).unwrap() +} + +/// Every key of §7.2's table has a vector that fails `acc32` by that parameter +/// condition alone: its graph meets `acc64`, every interval fits `acc32`, and its one +/// node's only failure is that key. +#[test] +fn each_acc32_parameter_key_fails_alone() { + let want = ["rq.mult", "rq.shift", "rq.post_bias", "weights", "chscale.m", "chscale.s", "igdn.gamma", "igdn.shift", "leaky.a"]; + let mut seen: Vec = Vec::new(); + for op in ["rescale", "conv", "conv_transpose", "chscale", "igdn", "leaky"] { + for v in lines(&format!("vectors/{op}.jsonl")) { + if !v.get("id").unwrap().as_str().unwrap().contains("/acc32_param/") { + continue; + } + let g = graph_of(&v); + let sizes = plan::load_plan(&g).unwrap(); + let b = bounds::pass(&g, sizes.as_deref()).unwrap(); + assert!(b.meets(&g, Profile::Acc64)); + let n = &b.nodes[0]; + assert!(n.inter.iter().all(|i| i.iv.fits(i.class.width(Profile::Acc32))), "{op}: an interval fails acc32"); + assert!(n.results.iter().all(|r| r.fits(32))); + assert_eq!(n.params32.len(), 1, "{op}: {:?}", n.params32); + let f = b.first_failure(&g, Profile::Acc32).unwrap(); + assert_eq!(f.miss.key, n.params32[0]); + seen.push(f.miss.key.clone()); + } + } + // `weights` has one for each of `conv` and `conv_transpose`. + seen.sort(); + seen.dedup(); + let mut w: Vec = want.iter().map(|s| s.to_string()).collect(); + w.sort(); + assert_eq!(seen, w); +} + +/// `sigmoid` and `elu` at −2^63 fail `acc64` through `exp.negx`, at 65 bits; an `rq` +/// whose `q` passes 64 bits fails at `rq.q` while `rq.y` fits where a `post` bias +/// brings it back. Without a bias (`chscale`, `mul`) `y` and the producer result pass +/// with `q`, at the same bits, and `out.0` is the smallest key of the three. +#[test] +fn step8_refusals_fail_where_the_text_says() { + for (file, key) in [("sigmoid", "exp.negx"), ("elu", "exp.negx"), ("rescale", "rq.q"), ("conv", "rq.q"), ("conv_transpose", "rq.q"), ("chscale", "out.0"), ("mul", "out.0")] { + let mut n = 0; + for v in lines(&format!("vectors/{file}.jsonl")) { + let id = v.get("id").unwrap().as_str().unwrap(); + if !(id.contains("/step8/") || id.contains("/step8_q/")) || v.get("load").unwrap().as_str() == Some("ok") { + continue; + } + let g = graph_of(&v); + let b = bounds::pass(&g, None).unwrap(); + let f = b.first_failure(&g, Profile::Acc64).unwrap(); + assert_eq!((f.miss.key.as_str(), f.miss.bits), (key, Some(65)), "{id}"); + if matches!(file, "rescale" | "conv" | "conv_transpose") { + let y = b.nodes[0].inter.iter().find(|i| i.key == "rq.y").unwrap(); + assert!(y.iv.fits(64), "{id}: y fits"); + } + n += 1; + } + assert!(n > 0, "{file}: no step-8 refusal"); + } +} diff --git a/wai/wai-verify/Cargo.lock b/wai/wai-verify/Cargo.lock index 5e6cc7ea5..8a7ed9c5a 100644 --- a/wai/wai-verify/Cargo.lock +++ b/wai/wai-verify/Cargo.lock @@ -2,6 +2,13 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "wai-ops" +version = "0.1.0" + [[package]] name = "wai-verify" version = "0.1.0" +dependencies = [ + "wai-ops", +] diff --git a/wai/wai-verify/Cargo.toml b/wai/wai-verify/Cargo.toml index 93361d19c..d97a69ed8 100644 --- a/wai/wai-verify/Cargo.toml +++ b/wai/wai-verify/Cargo.toml @@ -17,7 +17,20 @@ publish = false # `cfg(kani)` is set by the model checker on the included sources. Declared so an # ordinary build or clippy run of this crate does not warn on it. [lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ["cfg(kani)"] } +unexpected_cfgs = { level = "warn", check-cfg = ["cfg(kani)", "cfg(kani_open)"] } [dependencies] -# none — the integer core this crate verifies is pure std. +# None for the library: the integer core this crate verifies is pure std. The +# `wai-verify` tool (the bounds certifier, the lowerings and the conformance corpus +# of `wai-ops/1`) drives the `wai-ops` crate, behind the `cli` feature, so that the +# model checker's compilation environment stays the included sources and nothing +# else. +wai-ops = { path = "../wai-ops", optional = true } + +[features] +cli = ["dep:wai-ops"] + +[[bin]] +name = "wai-verify" +path = "src/bin/wai-verify/main.rs" +required-features = ["cli"] diff --git a/wai/wai-verify/check_shards.py b/wai/wai-verify/check_shards.py new file mode 100644 index 000000000..7dd073bc3 --- /dev/null +++ b/wai/wai-verify/check_shards.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +"""Every model-checker harness this crate hosts runs in exactly one shard. + +`.github/workflows/wai-formal-verification.yml` splits the harnesses into shards, each +a list of `--harness` filters (a harness runs when its full name contains a filter). +This finds every `#[kani::proof]` function in the sources `src/lib.rs` includes by +`#[path]` (with the modules those files declare in turn), gives each its full name, +and fails unless each name is matched by the filters of exactly one shard, and each +filter matches at least one harness. A harness no shard runs would be compiled and +never checked; one in two shards would be checked twice. A harness gated by +`cfg(kani_open)` (one whose window the checker did not finish within a shard's +budget) is compiled only on request, so no shard runs it; it is counted apart. + +Usage: python3 -I check_shards.py +Standard library only. +""" + +import os +import re +import sys + +PATH_MOD = re.compile(r'#\[path = "([^"]+)"\]\s*(?:pub(?:\(crate\))? )?mod (\w+);') +PLAIN_MOD = re.compile(r'^(?:pub(?:\(crate\))? )?mod (\w+);', re.M) +PROOF = re.compile(r'(#\[cfg\(kani_open\)\]\s*)?#\[kani::proof\]\s*(?:#\[[^\]]*\]\s*)*(?:pub(?:\(crate\))? )?fn (\w+)') +# A matrix line names its shard first and its filters last; between them it may give +# other plain fields, such as the runner (`os: macos`). +SHARD = re.compile(r'^\s*- \{ shard: ([\w-]+),(?: *[\w-]+: [\w-]+,)* *harness: "([^"]*)"', re.M) +MATRIX_LINE = re.compile(r'^\s*- \{ shard: ', re.M) + + +OPEN = [] + + +def harnesses(path, prefix, out): + """The harnesses of the module in `path` and of the modules it declares. A harness + gated by `cfg(kani_open)` is compiled only on request and runs in no shard; it is + listed apart.""" + src = open(path, encoding="utf-8").read() + for gated, name in PROOF.findall(src): + (OPEN if gated else out).append(prefix + name) + base = os.path.dirname(path) + stem = os.path.splitext(os.path.basename(path))[0] + # A `mod x;` in a.rs is a/x.rs or a/x/mod.rs; in mod.rs or lib.rs, x.rs beside it. + here = base if stem in ("mod", "lib") else os.path.join(base, stem) + for name in PLAIN_MOD.findall(src): + for cand in (os.path.join(here, name + ".rs"), os.path.join(here, name, "mod.rs")): + if os.path.exists(cand): + harnesses(cand, prefix + name + "::", out) + break + + +def main(root): + lib = os.path.join(root, "wai", "wai-verify", "src", "lib.rs") + src = open(lib, encoding="utf-8").read() + names = [] + for rel, name in PATH_MOD.findall(src): + harnesses(os.path.normpath(os.path.join(os.path.dirname(lib), rel)), name + "::", names) + wf = open(os.path.join(root, ".github", "workflows", "wai-formal-verification.yml"), encoding="utf-8").read() + shards = [(s, f.split()) for s, f in SHARD.findall(wf)] + failures = 0 + if not names or not shards: + print("FAIL no harnesses or no shards found") + return 1 + # A shard line this cannot read would drop its filters unseen. + if len(shards) != len(MATRIX_LINE.findall(wf)): + print("FAIL %d shard lines, %d read" % (len(MATRIX_LINE.findall(wf)), len(shards))) + return 1 + for n in names: + hit = [s for s, fs in shards if any(f in n for f in fs)] + if len(hit) != 1: + print("FAIL harness %s is in %d shards: %s" % (n, len(hit), ", ".join(hit) or "none")) + failures += 1 + for s, fs in shards: + for f in fs: + if not any(f in n for n in names): + print("FAIL shard %s: the filter %s matches no harness" % (s, f)) + failures += 1 + print("%d harnesses in %d shards; %d gated by cfg(kani_open), in none" % (len(names), len(shards), len(OPEN))) + for s, fs in shards: + print(" %-14s %d" % (s, sum(1 for n in names if any(f in n for f in fs)))) + return 1 if failures else 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1] if len(sys.argv) > 1 else ".")) diff --git a/wai/wai-verify/src/bin/wai-verify/corpus.rs b/wai/wai-verify/src/bin/wai-verify/corpus.rs new file mode 100644 index 000000000..4a92c4ded --- /dev/null +++ b/wai/wai-verify/src/bin/wai-verify/corpus.rs @@ -0,0 +1,285 @@ +//! `wai-verify vectors`: the conformance corpus of `wai/ops-conformance/` (§14). +//! +//! - `gen ` writes every file of `/ops-conformance` but its README +//! and `.gitattributes`: the vector files, the lowered graphs and the certificates. +//! - `verify ` recomputes every vector file from its inputs; re-lowers every +//! set that `certificates/index.json` and `certificates/falsification.json` list, +//! recomputes its certificate from the committed lowered graphs, and checks that a +//! falsification set's verdict fails the profile it is checked against; checks the +//! certificates of the sets that are not committed, which `external.json` lists, as +//! far as they can be checked without their sets; then regenerates the corpus. +//! Every byte must equal the committed one. +//! - `recompute ` recomputes one vector file to stdout. + +use std::path::{Path, PathBuf}; +use std::process::ExitCode; + +use wai_ops::bounds::{self, Profile}; +use wai_ops::generate::{self, sets}; +use wai_ops::json; +use wai_ops::vectors::{self, Kind}; + +fn kind_of(rel: &str) -> Option { + if !rel.ends_with(".jsonl") { + return None; + } + if rel.starts_with("stage/") { Some(Kind::Stage) } else { Some(Kind::Graph) } +} + +fn reader(wai: &Path) -> impl Fn(&str) -> Option> + '_ { + move |p: &str| std::fs::read(wai.join(p)).ok() +} + +pub fn write(wai: &Path) -> ExitCode { + let read = reader(wai); + let (files, dropped) = match generate::all(&read) { + Ok(x) => x, + Err(e) => { + eprintln!("gen: {e}"); + return ExitCode::from(2); + } + }; + let root = wai.join("ops-conformance"); + for (rel, bytes) in &files { + let p = root.join(rel); + if let Some(d) = p.parent() { + std::fs::create_dir_all(d).expect("create directory"); + } + std::fs::write(&p, bytes).expect("write"); + } + let lines: usize = files.iter().filter(|(r, _)| r.ends_with(".jsonl")).map(|(_, b)| b.iter().filter(|&&c| c == b'\n').count()).sum(); + let certs = files.iter().filter(|(r, _)| r.starts_with("certificates/") && r.ends_with(".json") && r.matches('/').count() == 2).count(); + eprintln!("wrote {} files, {} vectors, {} certificates", files.len(), lines, certs); + for (f, d) in dropped.iter().filter(|(_, d)| *d > 0) { + eprintln!(" {f}: {d} cases were not written"); + } + ExitCode::SUCCESS +} + +fn list(dir: &Path, base: &Path, out: &mut Vec) { + let Ok(rd) = std::fs::read_dir(dir) else { return }; + let mut v: Vec = rd.filter_map(|e| e.ok().map(|e| e.path())).collect(); + v.sort(); + for p in v { + if p.is_dir() { + list(&p, base, out); + } else { + out.push(p.strip_prefix(base).expect("below base").to_path_buf()); + } + } +} + +/// The sets a listing names, or the error that it cannot be read. +fn listing(root: &Path, name: &str) -> Result, String> { + let b = std::fs::read(root.join("certificates").join(name)).map_err(|e| format!("certificates/{name}: {e}"))?; + let v = json::parse(&b).map_err(|_| format!("certificates/{name} does not parse"))?; + Ok(v.get("sets").and_then(|s| s.as_arr()).map(|a| a.to_vec()).unwrap_or_default()) +} + +pub fn verify(wai: &Path) -> ExitCode { + let root = wai.join("ops-conformance"); + let mut bad = 0usize; + // 1. Every committed vector file, recomputed from its inputs. + let mut committed = Vec::new(); + list(&root, &root, &mut committed); + let (mut nfiles, mut nlines) = (0usize, 0usize); + for rel in &committed { + let r = rel.to_string_lossy().replace('\\', "/"); + let Some(kind) = kind_of(&r) else { continue }; + let text = std::fs::read_to_string(root.join(rel)).expect("read"); + nfiles += 1; + nlines += text.lines().count(); + match vectors::recompute_file(kind, &text) { + Ok(out) if out == text => {} + Ok(out) => { + bad += 1; + let n = out.lines().zip(text.lines()).position(|(a, b)| a != b).map_or(out.lines().count().min(text.lines().count()), |n| n); + eprintln!("DIFF {r}: line {} differs when recomputed", n + 1); + } + Err(e) => { + bad += 1; + eprintln!("FAIL {r}: {e}"); + } + } + } + eprintln!("recomputed {nfiles} vector files, {nlines} vectors"); + // 2. Every set, re-lowered and certified from its committed lowered graphs. + let read = reader(wai); + let mut n = 0; + for (list_name, falsify) in [("index.json", false), ("falsification.json", true)] { + match listing(&root, list_name) { + Ok(sets) => { + for s in &sets { + n += 1; + if let Err(e) = check_set(s, &read, wai, falsify) { + bad += 1; + eprintln!("FAIL {} {}: {e}", list_name, s.get("name").and_then(|v| v.as_str()).unwrap_or("?")); + } + } + } + Err(e) => { + bad += 1; + eprintln!("FAIL {e}"); + } + } + } + eprintln!("re-lowered and certified {n} sets"); + // 3. The certificates of the sets that are not committed, which the jobs that + // regenerate or fetch them check by digest: each is canonical, names its set, + // and its verdict meets the profile the listing gives. + match listing(&root, "external.json") { + Ok(sets) => { + for s in &sets { + if let Err(e) = check_external(s, &root) { + bad += 1; + eprintln!("FAIL external.json {}: {e}", s.get("name").and_then(|v| v.as_str()).unwrap_or("?")); + } + } + eprintln!("checked {} external certificates", sets.len()); + } + Err(e) => { + bad += 1; + eprintln!("FAIL {e}"); + } + } + // 4. The generator writes the committed corpus again, byte for byte, and nothing + // is committed that it does not write (the README aside). + match generate::all(&read) { + Ok((files, _)) => { + let mut want: Vec = Vec::new(); + for (rel, bytes) in &files { + want.push(rel.clone()); + match std::fs::read(root.join(rel)) { + Ok(c) if &c == bytes => {} + Ok(_) => { + bad += 1; + eprintln!("DIFF {rel}: the generator writes other bytes"); + } + Err(_) => { + bad += 1; + eprintln!("MISSING {rel}"); + } + } + } + // The external sets' certificates, and their listing, are written by the + // jobs that hold those sets. + let external: Vec = match listing(&root, "external.json") { + Ok(sets) => sets + .iter() + .filter_map(|s| Some(format!("certificates/{}/{}.json", s.get("capability")?.as_str()?, s.get("set_sha256")?.as_str()?))) + .chain([String::from("certificates/external.json")]) + .collect(), + Err(_) => vec![], + }; + for rel in &committed { + let r = rel.to_string_lossy().replace('\\', "/"); + if r != "README.md" && r != ".gitattributes" && !want.contains(&r) && !external.contains(&r) { + bad += 1; + eprintln!("EXTRA {r}: committed, but the generator does not write it"); + } + } + eprintln!("regenerated {} files", files.len()); + } + Err(e) => { + bad += 1; + eprintln!("FAIL gen: {e}"); + } + } + if bad == 0 { + eprintln!("ops-conformance: every file verifies"); + ExitCode::SUCCESS + } else { + eprintln!("ops-conformance: {bad} failures"); + ExitCode::from(1) + } +} + +/// Re-lower one listed set and compare its graphs; certify the committed graphs and +/// compare the certificate; for a falsification set, require that its verdict fails +/// the profile it claims. +fn check_set(s: &json::Value, read: &dyn Fn(&str) -> Option>, wai: &Path, falsify: bool) -> Result<(), String> { + let name = s.get("name").and_then(|v| v.as_str()).ok_or("name")?; + let cap = s.get("capability").and_then(|v| v.as_str()).ok_or("capability")?; + let lowering = s.get("lowering").and_then(|v| v.as_str()).ok_or("lowering")?; + let digest_listed = s.get("set_sha256").and_then(|v| v.as_str()).ok_or("set_sha256")?; + let c = s.get("c").and_then(|v| v.as_dec()).and_then(|v| v.to_i64()).map(|v| v as u32); + let members: Vec<(String, String)> = + s.get("members").and_then(|v| v.as_obj()).ok_or("members")?.iter().map(|(k, v)| (k.clone(), v.as_str().unwrap_or("").to_string())).collect(); + let mut bytes = Vec::new(); + for (k, p) in &members { + bytes.push((k.clone(), read(p).ok_or_else(|| format!("cannot read {p}"))?)); + } + let m: Vec<(&str, Vec)> = bytes.iter().map(|(k, b)| (k.as_str(), b.clone())).collect(); + let digest = sets::set_digest(&m); + if digest != digest_listed { + return Err(format!("set digest {digest} differs")); + } + let leak = |x: &str| -> &'static str { Box::leak(x.to_string().into_boxed_str()) }; + let set = sets::Set { name: leak(name), capability: leak(cap), lowering: leak(lowering), members: vec![], c, note: "" }; + let l = sets::lower_set(&set, &m)?; + let paths: Vec<&str> = s.get("roles").and_then(|v| v.as_arr()).ok_or("roles")?.iter().filter_map(|v| v.as_str()).collect(); + if paths.len() != l.roles.len() { + return Err("the roles differ".into()); + } + let mut graphs: Vec<(&str, Vec)> = Vec::new(); + for ((role, g), p) in l.roles.iter().zip(paths) { + let want = std::fs::read(wai.join(p)).map_err(|e| format!("{p}: {e}"))?; + if want != g.to_bytes() { + return Err(format!("{role}: the lowered graph differs from {p}")); + } + graphs.push((role, want)); + } + let refs: Vec<(&str, &[u8])> = graphs.iter().map(|(r, b)| (*r, b.as_slice())).collect(); + let cert = bounds::certify(Some(cap), lowering, Some(&digest), &refs).map_err(|e| format!("{} cannot be certified: {:?}", e.name, e.refusal))?; + let path = format!("ops-conformance/certificates/{cap}/{digest}.json"); + let committed = std::fs::read(wai.join(&path)).map_err(|e| format!("{path}: {e}"))?; + if committed != cert.to_json().into_bytes() { + return Err(format!("{path}: the certificate differs")); + } + if falsify { + let claim = s.get("claim").and_then(|v| v.as_str()).and_then(Profile::parse).ok_or("claim")?; + if cert.verdict().meets(claim) { + return Err(format!("its verdict meets {}, which it is there to fail", claim.as_str())); + } + } + Ok(()) +} + +fn check_external(s: &json::Value, root: &Path) -> Result<(), String> { + let cap = s.get("capability").and_then(|v| v.as_str()).ok_or("capability")?; + let digest = s.get("set_sha256").and_then(|v| v.as_str()).ok_or("set_sha256")?; + let profile = s.get("profile").and_then(|v| v.as_str()).and_then(Profile::parse).ok_or("profile")?; + let lowering = s.get("lowering").and_then(|v| v.as_str()).ok_or("lowering")?; + let path = format!("certificates/{cap}/{digest}.json"); + let b = std::fs::read(root.join(&path)).map_err(|e| format!("{path}: {e}"))?; + let v = json::parse(&b).map_err(|_| format!("{path} does not parse"))?; + let c = vectors::value_to_c(&v)?; + if json::to_string(&c).into_bytes() != b { + return Err(format!("{path} is not canonical")); + } + let field = |k: &str| v.get(k).and_then(|x| x.as_str()); + if field("capability") != Some(cap) || field("set_sha256") != Some(digest) || field("lowering") != Some(lowering) || field("certificate") != Some("wai-ops/1 bounds") { + return Err(format!("{path} names another set")); + } + let verdict = v.get("verdict").ok_or("verdict")?; + if verdict.get(profile.as_str()).and_then(|x| x.as_bool()) != Some(true) { + return Err(format!("{path}: its verdict does not meet {}", profile.as_str())); + } + Ok(()) +} + +pub fn recompute(file: &str) -> ExitCode { + let p = Path::new(file); + let rel = p.to_string_lossy(); + let kind = if rel.contains("/stage/") || rel.starts_with("stage/") { Kind::Stage } else { Kind::Graph }; + match std::fs::read_to_string(p).map_err(|e| e.to_string()).and_then(|t| vectors::recompute_file(kind, &t)) { + Ok(out) => { + print!("{out}"); + ExitCode::SUCCESS + } + Err(e) => { + eprintln!("{e}"); + ExitCode::from(2) + } + } +} diff --git a/wai/wai-verify/src/bin/wai-verify/main.rs b/wai/wai-verify/src/bin/wai-verify/main.rs new file mode 100644 index 000000000..f953f1a71 --- /dev/null +++ b/wai/wai-verify/src/bin/wai-verify/main.rs @@ -0,0 +1,459 @@ +//! `wai-verify`: the bounds certifier, the lowerings and the conformance corpus of +//! `wai-ops/1` (`extensions/integer-operators.md` §8, §13, §14). +//! +//! ```text +//! wai-verify bounds ... | [--capability ] [--lowering ] +//! [--member =]... [--c ] [--profile acc32|acc64] +//! [--out ] [--check ] +//! [--advise acc32|acc64] [--witness ] +//! wai-verify lower --capability [--member =]... [--c ] +//! --out +//! wai-verify vectors gen|verify +//! wai-verify vectors recompute +//! ``` +//! +//! A legacy set is a file (a one-file set) or a directory, whose every file is a +//! member named by its path below the directory, as a `wai.prior.set` listing names +//! it; `--member` adds a member, or names one whose file is named otherwise. The +//! capability selects the lowering (§13.0) and its declared profile, `acc64` for +//! every lowering of §13; `--c` is `world/1`'s latent channel count. `WHG1` graphs +//! are certified on their own, in the order given, with the lowering `"whg1"`. +//! +//! The certificate (§8.5) goes to `--out`, or to stdout. The verdict, the first +//! failure, the witnesses' paths and the advice go to stderr. +//! +//! Exit status: +//! - 0: the certificate was written and its verdict meets the profile; +//! - 1: the verdict fails the profile (the certificate is still written); +//! - 2: malformed input: a graph refused at load steps 1–7, an empty `check` +//! intersection or a `lut16` range past `[−32767, 32767]`, or an unreadable file; +//! - 3: `--check` found a difference, printed as the first differing JSON path; +//! - 4: the lowering refused the set; +//! - 5: usage. +//! +//! For `vectors`, 0 when every file verifies, 1 on a difference, 2 on an error. + +mod corpus; +mod witness; + +use std::path::{Path, PathBuf}; +use std::process::ExitCode; + +use wai_ops::bounds::{self, Certificate, Profile}; +use wai_ops::generate::sets; +use wai_ops::json::{self, C, Value}; + +const USAGE: &str = "usage: + wai-verify bounds ... | [--capability ] [--lowering ] + [--member =]... [--c ] [--profile acc32|acc64] + [--out ] [--check ] + [--advise acc32|acc64] [--witness ] + wai-verify lower --capability [--member =]... [--c ] --out + wai-verify vectors gen|verify + wai-verify vectors recompute "; + +fn usage(why: &str) -> ExitCode { + if !why.is_empty() { + eprintln!("wai-verify: {why}"); + } + eprintln!("{USAGE}"); + ExitCode::from(5) +} + +/// The lowering of §13.0's table for a capability. +fn lowering_of(cap: &str) -> Option<&'static str> { + Some(match cap { + "wai.neural.int_synth" => "int_synth/1", + "wai.neural.int_hyper" | "wai.video.int_hyper" | "wai.splat.int_codec" => "whm1/1", + "wai.audio.int_codec" => "wam1/1", + "wai.neural.int_mlicpp" => "wmb1/1", + "wai.world.model" => "world/1", + "wai.image.jpegai" => "jpegai-int/1", + _ => return None, + }) +} + +/// The member name of a one-file set of the capability. +fn one_file_member(cap: &str) -> Option<&'static str> { + Some(match cap { + "wai.neural.int_synth" => "int_synth.json", + "wai.audio.int_codec" => "model.wam", + "wai.splat.int_codec" => "g_s.whm", + "wai.neural.int_mlicpp" => "model.wmb", + _ => return None, + }) +} + +#[derive(Default)] +struct Args { + paths: Vec, + capability: Option, + lowering: Option, + members: Vec<(String, String)>, + c: Option, + profile: Option, + out: Option, + check: Option, + advise: Option, + witness: Option, +} + +fn parse_args(a: &[String]) -> Result { + let mut r = Args::default(); + let mut k = 0; + while k < a.len() { + let flag = a[k].as_str(); + let val = |k: usize| a.get(k + 1).cloned().ok_or_else(|| format!("{flag} takes a value")); + match flag { + "--capability" => r.capability = Some(val(k)?), + "--lowering" => r.lowering = Some(val(k)?), + "--member" => { + let v = val(k)?; + let (n, p) = v.split_once('=').ok_or("--member takes =")?; + r.members.push((n.to_string(), p.to_string())); + } + "--c" => r.c = Some(val(k)?.parse().map_err(|_| "--c takes a channel count")?), + "--profile" => r.profile = Some(Profile::parse(&val(k)?).ok_or("--profile is acc32 or acc64")?), + "--advise" => r.advise = Some(Profile::parse(&val(k)?).ok_or("--advise is acc32 or acc64")?), + "--out" => r.out = Some(val(k)?), + "--check" => r.check = Some(val(k)?), + "--witness" => r.witness = Some(val(k)?), + f if f.starts_with("--") => return Err(format!("unknown option {f}")), + _ => { + r.paths.push(a[k].clone()); + k += 1; + continue; + } + } + k += 2; + } + Ok(r) +} + +fn files_below(dir: &Path, base: &Path, out: &mut Vec<(String, PathBuf)>) -> std::io::Result<()> { + let mut v: Vec = std::fs::read_dir(dir)?.filter_map(|e| e.ok().map(|e| e.path())).collect(); + v.sort(); + for p in v { + if p.is_dir() { + files_below(&p, base, out)?; + } else { + let rel = p.strip_prefix(base).expect("below base").to_string_lossy().replace('\\', "/"); + out.push((rel, p)); + } + } + Ok(()) +} + +/// A set's members, by name, from its path and the `--member` options. +fn members(args: &Args, cap: &str) -> Result)>, String> { + let mut m: Vec<(String, PathBuf)> = Vec::new(); + for p in &args.paths { + let pb = PathBuf::from(p); + if pb.is_dir() { + files_below(&pb, &pb, &mut m).map_err(|e| format!("{p}: {e}"))?; + } else { + let n = one_file_member(cap).ok_or_else(|| format!("{cap} is a set of several files: give a directory or --member"))?; + m.push((n.to_string(), pb)); + } + } + for (n, p) in &args.members { + m.retain(|(k, _)| k != n); + m.push((n.clone(), PathBuf::from(p))); + } + let mut out = Vec::new(); + for (n, p) in m { + out.push((n, std::fs::read(&p).map_err(|e| format!("{}: {e}", p.display()))?)); + } + out.sort_by(|a, b| a.0.as_bytes().cmp(b.0.as_bytes())); + Ok(out) +} + +/// Either the certificate, or the exit code and message of why there is none. +type Certified = Result; + +fn certify(args: &Args) -> Certified { + let whg1 = args.capability.is_none() || args.lowering.as_deref() == Some("whg1") || (!args.paths.is_empty() && args.paths.iter().all(|p| p.ends_with(".whg1"))); + let refused = |e: bounds::Uncertifiable| (2, format!("{}: refused at load ({:?} at {:?})", e.name, e.refusal.code, e.refusal.at)); + if whg1 { + if args.paths.is_empty() { + return Err((5, "no graph given".into())); + } + let mut gs: Vec<(String, Vec)> = Vec::new(); + for p in &args.paths { + let b = std::fs::read(p).map_err(|e| (2, format!("{p}: {e}")))?; + let name = Path::new(p).file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default(); + gs.push((name, b)); + } + let refs: Vec<(&str, &[u8])> = gs.iter().map(|(n, b)| (n.as_str(), b.as_slice())).collect(); + return bounds::certify(args.capability.as_deref(), "whg1", None, &refs).map_err(refused); + } + let cap = args.capability.clone().unwrap(); + let lowering = lowering_of(&cap).ok_or_else(|| (4, format!("{cap}: no lowering of §13 lowers it")))?; + if let Some(l) = &args.lowering + && l != lowering + { + return Err((4, format!("{cap} lowers by {lowering}, not {l}"))); + } + let m = members(args, &cap).map_err(|e| (2, e))?; + if m.is_empty() { + return Err((5, "no set given".into())); + } + let mv: Vec<(&str, Vec)> = m.iter().map(|(n, b)| (n.as_str(), b.clone())).collect(); + let digest = sets::set_digest(&mv); + let leak = |x: &str| -> &'static str { Box::leak(x.to_string().into_boxed_str()) }; + let set = sets::Set { name: "set", capability: leak(&cap), lowering, members: vec![], c: args.c, note: "" }; + let l = sets::lower_set(&set, &mv).map_err(|e| (4, e))?; + let bytes: Vec<(&str, Vec)> = l.roles.iter().map(|(r, g)| (*r, g.to_bytes())).collect(); + let refs: Vec<(&str, &[u8])> = bytes.iter().map(|(r, b)| (*r, b.as_slice())).collect(); + bounds::certify(Some(&cap), lowering, Some(&digest), &refs).map_err(refused) +} + +/// A JSON value shown in a message. +fn show(v: &Value) -> String { + match v { + Value::Null => "null".into(), + Value::Bool(b) => b.to_string(), + Value::Str(s) => format!("\"{s}\""), + Value::Num(n) => n.to_string(), + Value::Arr(a) => format!("[{} items]", a.len()), + Value::Obj(m) => format!("{{{} members}}", m.len()), + } +} + +fn step(path: &str, k: &str) -> String { + if !k.is_empty() && k.bytes().all(|c| c.is_ascii_alphanumeric() || c == b'_') { + if path.is_empty() { k.to_string() } else { format!("{path}.{k}") } + } else { + format!("{path}[\"{k}\"]") + } +} + +/// The first path at which two JSON values differ, with both values there. +fn first_diff(a: &Value, b: &Value, path: &str) -> Option<(String, String, String)> { + match (a, b) { + (Value::Arr(x), Value::Arr(y)) => { + for (k, (p, q)) in x.iter().zip(y).enumerate() { + if let Some(d) = first_diff(p, q, &format!("{path}[{k}]")) { + return Some(d); + } + } + if x.len() != y.len() { + return Some((format!("{path}.length"), x.len().to_string(), y.len().to_string())); + } + None + } + (Value::Obj(x), Value::Obj(y)) => { + let mut keys: Vec<&String> = x.iter().map(|(k, _)| k).chain(y.iter().map(|(k, _)| k)).collect(); + keys.sort_by(|p, q| p.as_bytes().cmp(q.as_bytes())); + keys.dedup(); + for k in keys { + let (p, q) = (x.iter().find(|(n, _)| n == k).map(|(_, v)| v), y.iter().find(|(n, _)| n == k).map(|(_, v)| v)); + match (p, q) { + (Some(p), Some(q)) => { + if let Some(d) = first_diff(p, q, &step(path, k)) { + return Some(d); + } + } + (p, q) => return Some((step(path, k), p.map_or("absent".into(), show), q.map_or("absent".into(), show))), + } + } + None + } + _ if a == b => None, + _ => Some((if path.is_empty() { "$".into() } else { path.to_string() }, show(a), show(b))), + } +} + +fn describe(f: &bounds::SetFailure) -> String { + let bits = f.failure.miss.bits.map_or(String::new(), |b| format!(", {b} bits")); + format!("graph {} {} {}: {}{bits}", f.graph, f.failure.at.as_str(), f.failure.index, f.failure.miss.key) +} + +fn iv_c(v: &bounds::Iv) -> C { + C::obj(vec![("hi", C::big(v.hi)), ("lo", C::big(v.lo))]) +} + +fn advise(cert: &Certificate, p: Profile) -> C { + let graphs = cert + .graphs + .iter() + .map(|cg| { + let rows = match bounds::advise(&cg.graph, cg.sizes.as_deref(), p) { + Ok(v) => C::Arr( + v.iter() + .map(|a| { + C::obj(vec![ + ("admissible", a.admissible.as_ref().map_or(C::Null, iv_c)), + ("clamp", a.clamp.as_ref().map_or(C::Null, iv_c)), + ("interval", iv_c(&a.interval)), + ("tensor", C::int(a.tensor as i128)), + ]) + }) + .collect(), + ), + Err(r) => C::s(&format!("refused: {:?}", r.code)), + }; + C::obj(vec![("name", C::s(&cg.name)), ("tensors", rows)]) + }) + .collect(); + C::obj(vec![("advise", C::s(p.as_str())), ("graphs", C::Arr(graphs))]) +} + +fn cmd_bounds(args: &Args) -> ExitCode { + let cert = match certify(args) { + Ok(c) => c, + Err((code, why)) => { + eprintln!("wai-verify bounds: {why}"); + return ExitCode::from(code); + } + }; + let profile = args.profile.unwrap_or(Profile::Acc64); + let text = cert.to_json(); + match &args.out { + Some(p) => { + if let Err(e) = std::fs::write(p, &text) { + eprintln!("wai-verify bounds: {p}: {e}"); + return ExitCode::from(2); + } + } + None => print!("{text}"), + } + let v = cert.verdict(); + eprintln!("set {}", cert.set_sha256.as_deref().unwrap_or("(graphs on their own)")); + for p in Profile::ALL { + match v.failure(p) { + None => eprintln!("{}: meets", p.as_str()), + Some(f) => eprintln!("{}: fails, first at {}", p.as_str(), describe(f)), + } + } + eprintln!("npu: {} (reasons {:?}, flags {:?})", v.npu(), v.npu_reasons, v.npu_flags); + let mut code = if v.meets(profile) { 0 } else { 1 }; + if let Some(dir) = &args.witness + && !v.meets(profile) + { + if let Err(e) = std::fs::create_dir_all(dir) { + eprintln!("wai-verify bounds: {dir}: {e}"); + return ExitCode::from(2); + } + for cg in &cert.graphs { + for n in cg.bounds.nodes.iter().filter(|n| !n.fits(profile)) { + let p = Path::new(dir).join(format!("{}-{}.json", cg.name, n.index)); + let w = json::to_string(&witness::witness(cg, n, profile)); + if let Err(e) = std::fs::write(&p, w) { + eprintln!("wai-verify bounds: {}: {e}", p.display()); + return ExitCode::from(2); + } + eprintln!("witness {}", p.display()); + } + } + } + if let Some(p) = args.advise { + eprintln!("{}", json::to_string(&advise(&cert, p))); + } + if let Some(c) = &args.check { + let committed = match std::fs::read(c) { + Ok(b) => b, + Err(e) => { + eprintln!("wai-verify bounds: {c}: {e}"); + return ExitCode::from(2); + } + }; + if committed != text.as_bytes() { + let d = match (json::parse(text.as_bytes()), json::parse(&committed)) { + (Ok(a), Ok(b)) => first_diff(&a, &b, ""), + _ => None, + }; + match d { + Some((path, got, want)) => eprintln!("--check: differs at {path}: computed {got}, committed {want}"), + None => eprintln!("--check: the bytes differ ({c} is not canonical)"), + } + code = 3; + } else { + eprintln!("--check: identical to {c}"); + } + } + ExitCode::from(code) +} + +fn cmd_lower(args: &Args) -> ExitCode { + let (Some(cap), Some(out)) = (&args.capability, &args.out) else { return usage("lower takes --capability and --out") }; + let Some(lowering) = lowering_of(cap) else { + eprintln!("wai-verify lower: {cap}: no lowering of §13 lowers it"); + return ExitCode::from(4); + }; + let m = match members(args, cap) { + Ok(m) if !m.is_empty() => m, + Ok(_) => return usage("no set given"), + Err(e) => { + eprintln!("wai-verify lower: {e}"); + return ExitCode::from(2); + } + }; + let mv: Vec<(&str, Vec)> = m.iter().map(|(n, b)| (n.as_str(), b.clone())).collect(); + let leak = |x: &str| -> &'static str { Box::leak(x.to_string().into_boxed_str()) }; + let set = sets::Set { name: "set", capability: leak(cap), lowering, members: vec![], c: args.c, note: "" }; + let l = match sets::lower_set(&set, &mv) { + Ok(l) => l, + Err(e) => { + eprintln!("wai-verify lower: {e}"); + return ExitCode::from(4); + } + }; + if let Err(e) = std::fs::create_dir_all(out) { + eprintln!("wai-verify lower: {out}: {e}"); + return ExitCode::from(2); + } + for (role, g) in &l.roles { + let p = Path::new(out).join(format!("{role}.whg1")); + if let Err(e) = std::fs::write(&p, g.to_bytes()) { + eprintln!("wai-verify lower: {}: {e}", p.display()); + return ExitCode::from(2); + } + eprintln!("{}", p.display()); + } + eprintln!("set {}", sets::set_digest(&mv)); + ExitCode::SUCCESS +} + +fn main() -> ExitCode { + let a: Vec = std::env::args().skip(1).collect(); + let s: Vec<&str> = a.iter().map(String::as_str).collect(); + match s.as_slice() { + ["vectors", "gen", dir] => corpus::write(Path::new(dir)), + ["vectors", "verify", dir] => corpus::verify(Path::new(dir)), + ["vectors", "recompute", file] => corpus::recompute(file), + ["bounds", rest @ ..] | ["lower", rest @ ..] => { + let args = match parse_args(&a[1..1 + rest.len()]) { + Ok(x) => x, + Err(e) => return usage(&e), + }; + if s[0] == "bounds" { cmd_bounds(&args) } else { cmd_lower(&args) } + } + _ => usage(""), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// `--check` reports the first differing path, with both values. + #[test] + fn first_diff_names_the_path() { + let a = json::parse(br#"{"graphs":[{"nodes":[{"intermediates":{"convT.acc":{"hi":"5","lo":"0"}}}]}],"verdict":{"acc32":true}}"#).unwrap(); + let b = json::parse(br#"{"graphs":[{"nodes":[{"intermediates":{"convT.acc":{"hi":"6","lo":"0"}}}]}],"verdict":{"acc32":false}}"#).unwrap(); + assert_eq!(first_diff(&a, &b, ""), Some(("graphs[0].nodes[0].intermediates[\"convT.acc\"].hi".into(), "\"5\"".into(), "\"6\"".into()))); + assert_eq!(first_diff(&a, &a, ""), None); + let c = json::parse(br#"{"verdict":{"acc32":true,"x":"1"}}"#).unwrap(); + let d = json::parse(br#"{"verdict":{"acc32":true}}"#).unwrap(); + assert_eq!(first_diff(&c, &d, ""), Some(("verdict.x".into(), "\"1\"".into(), "absent".into()))); + } + + #[test] + fn every_lowered_capability_has_its_lowering() { + for (cap, low) in [("wai.neural.int_synth", "int_synth/1"), ("wai.video.int_hyper", "whm1/1"), ("wai.audio.int_codec", "wam1/1"), ("wai.splat.int_codec", "whm1/1"), ("wai.neural.int_mlicpp", "wmb1/1"), ("wai.world.model", "world/1"), ("wai.image.jpegai", "jpegai-int/1")] { + assert_eq!(lowering_of(cap), Some(low)); + } + assert_eq!(lowering_of("wai.video.int_motion"), None); + } +} diff --git a/wai/wai-verify/src/bin/wai-verify/witness.rs b/wai/wai-verify/src/bin/wai-verify/witness.rs new file mode 100644 index 000000000..811ed9bcc --- /dev/null +++ b/wai/wai-verify/src/bin/wai-verify/witness.rs @@ -0,0 +1,271 @@ +//! `--witness`: a node-local graph for each node that fails the profile (Part 2.5 of +//! the design). +//! +//! A witness is a one-operator `WHG1` graph whose inputs carry the failing node's +//! input intervals as `check` ranges. For `conv` and `conv_transpose` it also holds an +//! input that attains the failing end of the accumulator's interval on the channel +//! (and, for `conv_transpose`, the residue) that attains it, `x = h` where the weight +//! is positive and `x = l` where it is negative for the upper end, and the exact +//! accumulator at that position. It shows that the rule is tight for the node in +//! isolation; it says nothing about whether a payload can reach that input. + +use wai_ops::bounds::{CertGraph, Class, Iv, Node, Profile}; +use wai_ops::graph::{CAP, Graph, InputRec, Op, Params, TensorRec, op_name, opcode}; +use wai_ops::json::{C, hex}; +use wai_ops::xint::I512; + +fn i(v: i64) -> I512 { + I512::from_i64(v) +} + +/// The value a tap's input takes to push the sum toward `up` (the upper end) or +/// away from it: the end of `[l, h]` that maximises (or minimises) `w·x`, or the +/// value nearest 0 for a zero weight. +fn pick(w: i64, l: i64, h: i64, up: bool) -> i64 { + match (w.signum(), up) { + (1, true) | (-1, false) => h, + (-1, true) | (1, false) => l, + _ => 0i64.clamp(l, h), + } +} + +/// The input tensor, the exact accumulator, the channel and the end, for a +/// convolution witness; `None` when the node is not a convolution. +/// The witness of a convolution: the operator, the input `(C, H, W, data)`, the exact +/// accumulator, the output channel and position `(y, x)` it lies at, and whether it +/// attains the upper end. +type ConvWitness = (Op, (u32, u32, u32, Vec), I512, u32, (u32, u32), bool); + +fn conv_witness(op: &Op, cin: u32, x: (i64, i64), acc: &Iv, width: u32) -> Option { + // The end that fails the width, or else the larger in magnitude. + let up = I512::bits(acc.hi, acc.hi) > width || (I512::bits(acc.lo, acc.lo) <= width && acc.hi.abs() >= acc.lo.abs()); + let (l, h) = x; + match &op.p { + Params::Conv { cout, kh, kw, groups, w_bytes, rq, w, .. } => { + let (cg, og) = (cin / groups, cout / groups); + let n = (cg * kh * kw) as usize; + // The channel whose partial-sum end is extreme. + let mut best: Option<(I512, u32)> = None; + for o in 0..*cout { + let ws = &w[o as usize * n..(o as usize + 1) * n]; + let b = i(rq.pre(o as usize)); + let mut s = if up { b.max(I512::ZERO) } else { b.min(I512::ZERO) }; + for &wv in ws { + let t = i(wv).mul(i(pick(wv, l, h, up))); + s = if up { s.add(t.max(I512::ZERO)) } else { s.add(t.min(I512::ZERO)) }; + } + let better = match best { + None => true, + Some((v, _)) => (up && s > v) || (!up && s < v), + }; + if better { + best = Some((s, o)); + } + } + let (_, o) = best?; + let g0 = (o / og) * cg; + let mut data = vec![0i64.clamp(l, h); (cin * kh * kw) as usize]; + let mut value = i(rq.pre(o as usize)); + for ci in 0..cg { + for k in 0..(kh * kw) { + let wv = w[o as usize * n + (ci * kh * kw + k) as usize]; + let xv = pick(wv, l, h, up); + data[((g0 + ci) * kh * kw + k) as usize] = xv; + value = value.add(i(wv).mul(i(xv))); + } + } + let p = Params::Conv { cout: *cout, kh: *kh, kw: *kw, sh: 1, sw: 1, ph: 0, pw: 0, groups: *groups, w_bytes: *w_bytes, rq: rq.clone(), w: w.clone() }; + let o2 = Op { code: opcode::CONV, ins: vec![0], outs: vec![1], p }; + Some((o2, (cin, *kh, *kw, data), value, o, (0, 0), up)) + } + Params::ConvT { cout, kh, kw, sh, sw, w_bytes, rq, w, .. } => { + let (rh, rw) = ((*sh).min(*kh), (*sw).min(*kw)); + let at = |ci: u32, o: u32, ii: u32, jj: u32| w[(((ci * cout + o) * kh + ii) * kw + jj) as usize]; + let mut best: Option<(I512, u32, u32, u32)> = None; + for o in 0..*cout { + let b = i(rq.pre(o as usize)); + for ry in 0..rh { + for rx in 0..rw { + let mut s = if up { b.max(I512::ZERO) } else { b.min(I512::ZERO) }; + for ci in 0..cin { + for ii in (ry..*kh).step_by(*sh as usize) { + for jj in (rx..*kw).step_by(*sw as usize) { + let wv = at(ci, o, ii, jj); + let t = i(wv).mul(i(pick(wv, l, h, up))); + s = if up { s.add(t.max(I512::ZERO)) } else { s.add(t.min(I512::ZERO)) }; + } + } + } + let better = match best { + None => true, + Some((v, ..)) => (up && s > v) || (!up && s < v), + }; + if better { + best = Some((s, o, ry, rx)); + } + } + } + } + let (_, o, ry, rx) = best?; + // With no padding, output (ρy + sh·(H − 1), ρx + sw·(W − 1)) reads tap + // (i, j) of residue ρ at input row H − 1 − (i − ρy)/sh, column likewise. + let (hh, ww) = (kh.div_ceil(*sh), kw.div_ceil(*sw)); + let mut data = vec![0i64.clamp(l, h); (cin * hh * ww) as usize]; + let mut value = i(rq.pre(o as usize)); + for ci in 0..cin { + for ii in (ry..*kh).step_by(*sh as usize) { + for jj in (rx..*kw).step_by(*sw as usize) { + let wv = at(ci, o, ii, jj); + let xv = pick(wv, l, h, up); + let (u, v) = (hh - 1 - (ii - ry) / sh, ww - 1 - (jj - rx) / sw); + data[((ci * hh + u) * ww + v) as usize] = xv; + value = value.add(i(wv).mul(i(xv))); + } + } + } + let p = Params::ConvT { cout: *cout, kh: *kh, kw: *kw, sh: *sh, sw: *sw, ph: 0, pw: 0, oph: 0, opw: 0, w_bytes: *w_bytes, rq: rq.clone(), w: w.clone() }; + let o2 = Op { code: opcode::CONV_TRANSPOSE, ins: vec![0], outs: vec![1], p }; + Some((o2, (cin, hh, ww, data), value, o, (ry + sh * (hh - 1), rx + sw * (ww - 1)), up)) + } + _ => None, + } +} + +/// The witness of node `n` of `cg`, failing `p`, as canonical JSON. +pub fn witness(cg: &CertGraph, n: &Node, p: Profile) -> C { + let g = &cg.graph; + let op = &g.ops[n.index as usize]; + let miss = n.miss(p).expect("a failing node"); + let ins: Vec = op.ins.iter().map(|&t| cg.bounds.tensors[t as usize]).collect(); + let fits = ins.iter().all(|v| v.fits(64)); + let mut m = vec![ + ("index", C::int(n.index as i128)), + ("key", C::s(&miss.key)), + ("op", C::s(op_name(op.code).unwrap_or("?"))), + ("profile", C::s(p.as_str())), + ("role", C::s(&cg.name)), + ]; + let acc = n.inter.iter().find(|x| x.key == "conv.acc" || x.key == "convT.acc"); + let cin = g.tensors[op.ins[0] as usize].channels; + if fits && !n.saturated { + let x = (ins[0].lo.to_i64().unwrap(), ins[0].hi.to_i64().unwrap()); + if let Some(a) = acc + && let Some((o2, (c, hh, ww, data), value, ch, (py, px), up)) = conv_witness(op, cin, x, &a.iv, Class::Acc.width(p)) + { + let out_c = g.tensors[op.outs[0] as usize].channels; + let gr = Graph { + max_elems: CAP as u32, + scalars: vec![], + inputs: vec![InputRec { tensor: 0, max_h: 0, max_w: 0, kind: 0, src: 0, init: 0 }], + outputs: vec![1], + tensors: vec![TensorRec::check(c, x.0, x.1), TensorRec::derived(out_c)], + ops: vec![o2], + }; + m.push(("graph", C::Str(hex(&gr.to_bytes())))); + m.push(("input", C::obj(vec![("data", C::ints(data.iter().map(|&v| v as i128))), ("shape", C::ints([c as i128, hh as i128, ww as i128]))]))); + m.push(("channel", C::int(ch as i128))); + m.push(("at", C::ints([py as i128, px as i128]))); + m.push(("end", C::s(if up { "hi" } else { "lo" }))); + m.push(("acc", C::big(value))); + return C::obj(m); + } + // Any other operator: the node alone, its inputs checked against its input + // intervals, with no input chosen. + let mut tensors = Vec::new(); + let mut inputs = Vec::new(); + let mut map: Vec<(u32, u32)> = Vec::new(); + for (&t, v) in op.ins.iter().zip(&ins) { + if map.iter().any(|(a, _)| *a == t) { + continue; + } + let k = tensors.len() as u32; + let (mh, mw) = cg.sizes.as_ref().map_or((0, 0), |s| (s[t as usize].0 as u32, s[t as usize].1 as u32)); + tensors.push(TensorRec::check(g.tensors[t as usize].channels, v.lo.to_i64().unwrap(), v.hi.to_i64().unwrap())); + inputs.push(InputRec { tensor: k, max_h: mh, max_w: mw, kind: 0, src: 0, init: 0 }); + map.push((t, k)); + } + let first_out = tensors.len() as u32; + for &t in &op.outs { + tensors.push(TensorRec::derived(g.tensors[t as usize].channels)); + } + let o2 = Op { + code: op.code, + ins: op.ins.iter().map(|t| map.iter().find(|(a, _)| a == t).unwrap().1).collect(), + outs: (first_out..first_out + op.outs.len() as u32).collect(), + p: op.p.clone(), + }; + let gr = Graph { max_elems: CAP as u32, scalars: g.scalars.clone(), inputs, outputs: o2.outs.clone(), tensors, ops: vec![o2] }; + m.push(("graph", C::Str(hex(&gr.to_bytes())))); + } else { + m.push(("graph", C::Null)); + } + m.push(("input", C::Null)); + C::obj(m) +} + +#[cfg(test)] +mod tests { + use super::*; + use wai_ops::bounds::{self, Profile}; + use wai_ops::interp::{Sequence, Tensor, run, run_observed}; + use wai_ops::json::{self, unhex}; + use wai_ops::{graph, lower}; + + /// The witness of the photo set's node 6 under `acc32`, run through the + /// interpreter: at the position it names, its output is the rounded accumulator + /// it records, and that accumulator is `convT.acc`'s upper end. + #[test] + fn the_photo_witness_attains_its_bound() { + let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../neural-conformance/vectors/photo/int_synth.json"); + let set = lower::int_synth(&std::fs::read(p).unwrap()).unwrap(); + let b = set.get("synth").unwrap().to_bytes(); + let cert = bounds::certify(None, "int_synth/1", None, &[("synth", &b)]).unwrap(); + let cg = &cert.graphs[0]; + let n = &cg.bounds.nodes[6]; + let w = json::parse(json::to_string(&witness(cg, n, Profile::Acc32)).as_bytes()).unwrap(); + let acc = w.get("acc").unwrap().as_dec().unwrap(); + assert_eq!(acc, n.inter.iter().find(|i| i.key == "convT.acc").unwrap().iv.hi); + let g = graph::load(&unhex(w.get("graph").unwrap().as_str().unwrap()).unwrap(), Profile::Acc64).unwrap(); + let inp = w.get("input").unwrap(); + let shape: Vec = inp.get("shape").unwrap().as_arr().unwrap().iter().map(|v| v.as_dec().unwrap().to_i64().unwrap() as u32).collect(); + let data: Vec = inp.get("data").unwrap().as_arr().unwrap().iter().map(|v| v.as_dec().unwrap().to_i64().unwrap()).collect(); + let out = run(&g, &[Tensor::new(shape[0], shape[1], shape[2], data)], &[], &mut Sequence::new()).unwrap().remove(0); + let ch = w.get("channel").unwrap().as_dec().unwrap().to_i64().unwrap() as usize; + let at: Vec = w.get("at").unwrap().as_arr().unwrap().iter().map(|v| v.as_dec().unwrap().to_i64().unwrap() as usize).collect(); + let shift = match &g.ops[0].p { + wai_ops::graph::Params::ConvT { rq, .. } => rq.shift(ch), + _ => unreachable!(), + }; + let got = out.data[(ch * out.h as usize + at[0]) * out.w as usize + at[1]]; + assert_eq!(I512::from_i64(got), acc.shr_floor(shift)); + } + + /// The same witness, run observed: every value the operator forms lies in the + /// interval the photo set's certificate records for node 6, and the accumulator + /// with its `pre` bias (`rq.t`, whose interval is `convT.acc`) reaches that + /// interval's upper end, so the end is attained, not only a bound. + #[test] + fn the_photo_witness_stays_in_its_certified_intervals() { + let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../neural-conformance/vectors/photo/int_synth.json"); + let set = lower::int_synth(&std::fs::read(p).unwrap()).unwrap(); + let b = set.get("synth").unwrap().to_bytes(); + let cert = bounds::certify(None, "int_synth/1", None, &[("synth", &b)]).unwrap(); + let n = &cert.graphs[0].bounds.nodes[6]; + let w = json::parse(json::to_string(&witness(&cert.graphs[0], n, Profile::Acc32)).as_bytes()).unwrap(); + let g = graph::load(&unhex(w.get("graph").unwrap().as_str().unwrap()).unwrap(), Profile::Acc64).unwrap(); + let inp = w.get("input").unwrap(); + let shape: Vec = inp.get("shape").unwrap().as_arr().unwrap().iter().map(|v| v.as_dec().unwrap().to_i64().unwrap() as u32).collect(); + let data: Vec = inp.get("data").unwrap().as_arr().unwrap().iter().map(|v| v.as_dec().unwrap().to_i64().unwrap()).collect(); + // The witness graph's one node is node 6 on node 6's input interval, so its pass + // gives node 6's intervals. + let wb = bounds::pass(&g, None).unwrap(); + assert_eq!(wb.nodes[0].inter, n.inter); + let mut obs = bounds::Within::new(&wb); + run_observed(&g, &[Tensor::new(shape[0], shape[1], shape[2], data)], &[], &mut Sequence::new(), &mut obs).unwrap(); + assert!(obs.outside.is_empty(), "{:?}", obs.outside); + assert!(obs.unrecorded.is_empty(), "{:?}", obs.unrecorded); + let hi = n.inter.iter().find(|i| i.key == "convT.acc").unwrap().iv.hi; + let (_, seen_hi) = obs.extreme(0, "rq.t").unwrap(); + assert_eq!(I512::from_i128(seen_hi), hi, "the accumulator with its bias attains convT.acc's upper end"); + } +} diff --git a/wai/wai-verify/src/lib.rs b/wai/wai-verify/src/lib.rs index a31cdbb8c..8c5e3ed39 100644 --- a/wai/wai-verify/src/lib.rs +++ b/wai/wai-verify/src/lib.rs @@ -7,10 +7,11 @@ //! arithmetic is checked for all inputs in a bounded window rather than for the //! vectors someone thought to write. //! -//! The harnesses live beside the code they verify, in `wai-rs`, behind -//! `#[cfg(kani)]`; this crate only supplies a minimal compilation environment -//! (no codec libraries, no ONNX, no MSRV floor above the verifier's toolchain). -//! One source of truth, exactly as the conformance crate does it. +//! The harnesses live beside the code they verify, in `wai-rs` and in `wai-ops` (the +//! integer operator set), behind `#[cfg(kani)]`; this crate only supplies a minimal +//! compilation environment (no codec libraries, no ONNX, no MSRV floor above the +//! verifier's toolchain). One source of truth, exactly as the conformance crate does +//! it. /// The integer rANS coder — the arithmetic every byte-exact decode flows /// through, and therefore the place the determinism claim is won or lost. @@ -30,9 +31,9 @@ pub mod int_entropy; #[path = "../../wai-rs/src/int_transform.rs"] pub mod int_transform; -/// The fast kernels `int_transform::igdn` dispatches to. Present so the included -/// sources compile (only IGDN uses it here, hence the dead-code allowance); no -/// harness reaches it, and it spawns no threads under the model checker. +/// The fast kernels `int_transform::igdn` dispatches to. Only IGDN is used here, hence +/// the dead-code allowance; the operator set's K10 checks its narrow paths against the +/// reference IGDN. It spawns no threads under the model checker. #[allow(dead_code)] #[path = "../../wai-rs/src/int_kernels.rs"] pub mod int_kernels; @@ -50,3 +51,53 @@ pub mod wai_video_policy; pub mod staged_predict; #[path = "../../wai-rs/src/staged/wir1_arith.rs"] pub mod staged_wir1_arith; + +// ---------------------------------------------------------------- wai-ops/1 +// +// The reference implementation of the integer operator set +// (`extensions/integer-operators.md`), included module by module at this crate's +// root, so that its `crate::` paths resolve here exactly as they do in `wai-ops`. +// Its harnesses (K1–K33 of the operator set's test plan) live in `wai-ops` behind +// `#[cfg(kani)]`, in `src/proofs/`, and run here. Only the model checker compiles +// these: the `wai-verify` tool reaches the same sources through the `wai-ops` +// dependency, so an ordinary build does not compile them twice. + +#[cfg(kani)] +extern crate alloc; + +#[cfg(kani)] +#[path = "../../wai-ops/src/code.rs"] +pub mod code; +#[cfg(kani)] +#[path = "../../wai-ops/src/xint.rs"] +pub mod xint; +#[cfg(kani)] +#[path = "../../wai-ops/src/json.rs"] +pub mod json; +#[cfg(kani)] +#[path = "../../wai-ops/src/sha256.rs"] +pub mod sha256; +#[cfg(kani)] +#[path = "../../wai-ops/src/graph.rs"] +pub mod graph; +#[cfg(kani)] +#[path = "../../wai-ops/src/plan.rs"] +pub mod plan; +#[cfg(kani)] +#[path = "../../wai-ops/src/interp.rs"] +pub mod interp; +#[cfg(kani)] +#[path = "../../wai-ops/src/bounds.rs"] +pub mod bounds; +#[cfg(kani)] +#[path = "../../wai-ops/src/limb32.rs"] +pub mod limb32; +#[cfg(kani)] +#[path = "../../wai-ops/src/lower/mod.rs"] +pub mod lower; +#[cfg(kani)] +#[path = "../../wai-ops/src/stage/mod.rs"] +pub mod stage; +#[cfg(kani)] +#[path = "../../wai-ops/src/proofs/mod.rs"] +mod proofs;