diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebf003f722..0ebe4bdc1a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,139 +12,181 @@ on: jobs: test_rust: - runs-on: ubuntu-latest-8-cores + runs-on: ubuntu-latest-8-cores steps: - - uses: actions/checkout@v4 - - - name: Set up Rust - uses: moonrepo/setup-rust@v1 - with: - components: clippy, llvm-tools-preview - cache: false - channel: 'nightly' - - - name: install grcov - run: if ! which grcov; then cargo install grcov; fi - - - name: Build Rust - env: - RUSTFLAGS: -Cinstrument-coverage - run: | - cd quadratic-core - cargo build - - - name: Test - env: - LLVM_PROFILE_FILE: grcov-%p-%m.profraw - RUSTFLAGS: -Cinstrument-coverage - run: | - cd quadratic-core - cargo test - - - name: Generate coverage - run: | - grcov $(find . -name "grcov-*.profraw" -print) \ - --branch \ - --ignore-not-existing \ - --binary-path ./quadratic-core/target/debug/ \ - -s . \ - -t lcov \ - --ignore "/*" \ - --ignore "./quadratic-core/src/wasm_bindings/*" \ - --ignore "./quadratic-core/src/bin/*" \ - -o lcov.info - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + - uses: actions/checkout@v4 + + - name: Set up Rust + uses: moonrepo/setup-rust@v1 + with: + components: clippy, llvm-tools-preview + cache: false + channel: "nightly" + + - name: Install grcov + run: if ! which grcov; then cargo install grcov; fi + + - name: Install llvm-tools-preview + run: if ! which llvm-tools-preview; then rustup component add llvm-tools-preview; fi + + - name: Install pkg-config + if: github.runner.isHosted == true + run: | + sudo apt-get update + sudo apt-get install -y pkg-config + + - name: Build quadratic-core + env: + RUSTFLAGS: -Cinstrument-coverage + run: | + cd quadratic-core + cargo build + + - name: Test quadratic-core + env: + LLVM_PROFILE_FILE: grcov-%p-%m.profraw + RUSTFLAGS: -Cinstrument-coverage + run: | + cd quadratic-core + cargo test + + - name: Generate coverage for quadratic-core + run: | + grcov $(find . -name "grcov-*.profraw" -print) \ + --branch \ + --ignore-not-existing \ + --binary-path ./target/debug/ \ + -s . \ + -t lcov \ + --ignore "/*" \ + --ignore "./src/wasm_bindings/*" \ + --ignore "./src/bin/*" \ + -o lcov.info + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + - name: Build quadratic-multiplayer + env: + RUSTFLAGS: -Cinstrument-coverage + run: | + cd quadratic-multiplayer + cargo build + + - name: Test quadratic-multiplayer + env: + LLVM_PROFILE_FILE: grcov-%p-%m.profraw + RUSTFLAGS: -Cinstrument-coverage + run: | + cd quadratic-multiplayer + cargo test # hangs forever + + - name: Generate coverage quadratic-multiplayer + run: | + grcov $(find . -name "grcov-*.profraw" -print) \ + --branch \ + --ignore-not-existing \ + --binary-path ./target/debug/ \ + -s . \ + -t lcov \ + --ignore "/*" \ + --ignore "./src/wasm_bindings/*" \ + --ignore "./src/bin/*" \ + -o lcov.info + + - name: Upload coverage reports to Codecov quadratic-multiplayer + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} test_unit: runs-on: ubuntu-latest-8-cores steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 18 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 - - name: Run npm test:ci in quadratic-client - run: | - cd quadratic-client - npm install - npm run test:unit + - name: Run npm test:ci in quadratic-client + run: | + cd quadratic-client + npm install + npm run test:unit test_python: runs-on: ubuntu-latest-8-cores steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 18 - - uses: actions/setup-python@v4 - with: - python-version: '3.9' - cache: 'pip' - - - name: Test python - run: | - pip install -r requirements.txt - cd quadratic-client - npm run test:python + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - uses: actions/setup-python@v4 + with: + python-version: "3.9" + cache: "pip" + + - name: Test python + run: | + pip install -r requirements.txt + cd quadratic-client + npm run test:python test_api: runs-on: ubuntu-latest-8-cores steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 18 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 - - name: Run npm test:ci in quadratic-client - run: | - cd quadratic-api - npm install - npm run docker:test:ci + - name: Run npm test:ci in quadratic-client + run: | + cd quadratic-api + npm install + npm run docker:test:ci lint_rust: runs-on: ubuntu-latest-8-cores steps: - - uses: actions/checkout@v4 - - name: Set up Rust - uses: moonrepo/setup-rust@v1 - with: - components: clippy - cache: false - - - name: Run cargo clippy in quadratic-core - run: | - cd quadratic-core - cargo clippy -- -D warnings - + - uses: actions/checkout@v4 + - name: Set up Rust + uses: moonrepo/setup-rust@v1 + with: + components: clippy + cache: false + + - name: Run cargo clippy in quadratic-core + run: | + cd quadratic-core + cargo clippy -- -D warnings + lint: runs-on: ubuntu-latest-8-cores steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 18 - - name: Set up Rust - uses: moonrepo/setup-rust@v1 - with: - cache: false - - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: 'latest' - - - name: Build wasm core - run: | - cd quadratic-client - npm run build:wasm:javascript:dev - npm run build:wasm:types - - - name: Lint quadratic-client - run: | - cd quadratic-client - npm install - npm run lint:prettier - npm run lint:eslint - npm run lint:ts + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - name: Set up Rust + uses: moonrepo/setup-rust@v1 + with: + cache: false + - uses: jetli/wasm-pack-action@v0.4.0 + with: + version: "latest" + + - name: Build wasm core + run: | + cd quadratic-client + npm run build:wasm:javascript:dev + npm run build:wasm:types + + - name: Lint quadratic-client + run: | + cd quadratic-client + npm install + npm run lint:prettier + npm run lint:eslint + npm run lint:ts diff --git a/.github/workflows/coverage-rust.yml b/.github/workflows/coverage-rust.yml deleted file mode 100644 index c6583aed4f..0000000000 --- a/.github/workflows/coverage-rust.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: Rust Test Coverage - -on: - push: - branches: - - main - pull_request: - -jobs: - test-coverage: - name: Test coverage - runs-on: ubuntu-latest-4-cores - - steps: - - name: Configure cache - uses: actions/cache@v3 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - quadratic-core/target/ - key: test-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Setup Rust - run: | - rustup toolchain add nightly --component llvm-tools-preview - rustup override set nightly - if ! which grcov; then cargo install grcov; fi - - - name: Build quadratic-core - env: - RUSTFLAGS: -Cinstrument-coverage - run: | - cd quadratic-core - cargo build - - - name: Test quadratic-core - env: - LLVM_PROFILE_FILE: grcov-%p-%m.profraw - RUSTFLAGS: -Cinstrument-coverage - run: | - cd quadratic-core - cargo test - - - name: Generate coverage quadratic-core - run: | - grcov $(find . -name "grcov-*.profraw" -print) \ - --branch \ - --ignore-not-existing \ - --binary-path ./quadratic-core/target/debug/ \ - -s . \ - -t lcov \ - --ignore "/*" \ - --ignore "./quadratic-core/src/wasm_bindings/*" \ - --ignore "./quadratic-core/src/bin/*" \ - -o lcov.info - - - name: Upload coverage reports to Codecov quadratic-core - uses: codecov/codecov-action@v3 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - - - name: Build quadratic-multiplayer - env: - RUSTFLAGS: -Cinstrument-coverage - run: | - cd quadratic-multiplayer - cargo build - - - name: Test quadratic-multiplayer - env: - LLVM_PROFILE_FILE: grcov-%p-%m.profraw - RUSTFLAGS: -Cinstrument-coverage - run: | - cd quadratic-multiplayer - cargo test - - - name: Generate coverage quadratic-multiplayer - run: | - grcov $(find . -name "grcov-*.profraw" -print) \ - --branch \ - --ignore-not-existing \ - --binary-path ./quadratic-multiplayer/target/debug/ \ - -s . \ - -t lcov \ - --ignore "/*" \ - --ignore "./quadratic-multiplayer/src/wasm_bindings/*" \ - --ignore "./quadratic-multiplayer/src/bin/*" \ - -o lcov.info - - - name: Upload coverage reports to Codecov quadratic-multiplayer - uses: codecov/codecov-action@v3 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - diff --git a/.github/workflows/preview-branches-close.yml b/.github/workflows/preview-branches-close.yml new file mode 100644 index 0000000000..a9447c3023 --- /dev/null +++ b/.github/workflows/preview-branches-close.yml @@ -0,0 +1,35 @@ +on: + pull_request: + types: [closed] + +# Use runs on `ubuntu-latest-8-cores`. All of our self hosted runners use this tag. +# Our runners pick up jobs first, and if all our runners are being used or are down +# it will automatically back up to using GitHub hosted runners. + +jobs: + teardown: + name: Destroy Pulumi Infrastructure Stack + runs-on: ubuntu-latest-8-cores + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - uses: pulumi/actions@v4 + + - name: Destroy Infrastructure Stack + working-directory: infra + run: | + npm ci + + STACK_NAME="preview-pr-${{ env.PR_ID }}" + pulumi stack select $STACK_NAME + pulumi config set aws:region us-west-2 + + pulumi destroy -y --remove + + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} + PR_ID: ${{ github.event.pull_request.number }} \ No newline at end of file diff --git a/.github/workflows/preview-branches.yml b/.github/workflows/preview-branches.yml new file mode 100644 index 0000000000..62ec956960 --- /dev/null +++ b/.github/workflows/preview-branches.yml @@ -0,0 +1,136 @@ +name: Deploy Preview Branch + +on: + pull_request: + + +# Use runs on `ubuntu-latest-8-cores`. All of our self hosted runners use this tag. +# Our runners pick up jobs first, and if all our runners are being used or are down +# it will automatically back up to using GitHub hosted runners. + + +jobs: + + infra: + name: Create or Update Infrastructure with Pulumi + runs-on: ubuntu-latest-8-cores + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - uses: pulumi/actions@v4 + + - name: Update Pulumi Infrastructure + id: pulumiInfra + working-directory: infra + run: | + npm ci + + STACK_NAME="preview-pr-${{ env.PR_ID }}" + if ! pulumi stack ls | grep -q "^$STACK_NAME"; then + echo "Stack $STACK_NAME does not exist. Initializing..." + pulumi stack init $STACK_NAME + else + echo "Stack $STACK_NAME already exists." + pulumi stack select $STACK_NAME + fi + + pulumi config set aws:region us-west-2 + pulumi config set domain quadratic-preview.com + pulumi config set subdomain multiplayer-pr-${{ env.PR_ID }} + pulumi config set data-dog-env preview + pulumi config set data-dog-api-key ${{ env.DD_API_KEY }} + + pulumi up -y + echo "MULTIPLAYER_INSTANCE_DNS=$(pulumi stack output multiplayerInstanceDns)" >> "$GITHUB_OUTPUT" + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} + PR_ID: ${{ github.event.pull_request.number }} + DD_API_KEY: ${{ secrets.DD_API_KEY }} + + outputs: + MULTIPLAYER_INSTANCE_DNS: ${{ steps.pulumiInfra.outputs.MULTIPLAYER_INSTANCE_DNS }} + + + multiplayer_preview: + needs: infra + runs-on: ubuntu-latest-8-cores + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Set up Rust + uses: moonrepo/setup-rust@v1 + with: + components: clippy, llvm-tools-preview + cache: false + channel: 'nightly' + + - name: Install pkg-config + if: github.runner.isHosted == true + run: | + sudo apt-get update + sudo apt-get install -y pkg-config + + - name: Build quadratic-multiplayer + working-directory: quadratic-multiplayer + run: | + cargo build --release + + - name: Deploy Multiplayer to EC2 + run: ./infra/multiplayer/deploy-multiplayer-service.sh + env: + EC2_KEY_PEM: ${{ secrets.EC2_KEY_PEM }} + EC2_INSTANCE_DNS: ${{needs.infra.outputs.MULTIPLAYER_INSTANCE_DNS}} + + # client_preview: + # needs: infra + # runs-on: ubuntu-latest-8-cores + # steps: + # - uses: actions/checkout@v4 + # - uses: actions/setup-node@v4 + # with: + # node-version: 18 + + # - name: Set up Rust + # uses: moonrepo/setup-rust@v1 + # with: + # cache: false + # - uses: jetli/wasm-pack-action@v0.4.0 + # with: + # version: 'latest' + + # - name: Build Client + # working-directory: quadratic-client + # run: | + # npm ci + # npm run build:wasm:javascript + # npm run build:wasm:types + # npm run build + # env: + # VITE_ENVIRONMENT: preview + # VITE_QUADRATIC_API_URL: https://quadratic-api-dev-pr-${{ github.event.pull_request.number }}.herokuapp.com + # VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} + # VITE_AUTH0_CLIENT_ID: ${{ secrets.VITE_AUTH0_CLIENT_ID }} + # VITE_AUTH0_AUDIENCE: ${{ secrets.VITE_AUTH0_AUDIENCE }} + # VITE_AUTH0_ISSUER: ${{ secrets.VITE_AUTH0_ISSUER }} + # VITE_AUTH0_DOMAIN: ${{ secrets.VITE_AUTH0_DOMAIN }} + + # # Set up AWS credentials + # - name: Set up AWS credentials + # uses: aws-actions/configure-aws-credentials@v1 + # with: + # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + # aws-region: your-aws-region + + # # Deploy to S3 + # - name: Deploy to S3 + # run: | + # aws s3 sync ./path-to-your-static-files/ s3://your-s3-bucket-name --delete + diff --git a/.github/workflows/production-deploy.yml b/.github/workflows/production-deploy.yml new file mode 100644 index 0000000000..e8bbc5770c --- /dev/null +++ b/.github/workflows/production-deploy.yml @@ -0,0 +1,86 @@ +name: Deploy to Production + +on: + push: + branches: + - main + paths: + - 'quadratic-multiplayer/**' + +# Use runs on `ubuntu-latest-8-cores`. All of our self hosted runners use this tag. +# Our runners pick up jobs first, and if all our runners are being used or are down +# it will automatically back up to using GitHub hosted runners. + + +jobs: + + infra_production: + name: Update Infrastructure with Pulumi + runs-on: ubuntu-latest-8-cores + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - uses: pulumi/actions@v4 + + - name: Update Pulumi Infrastructure + working-directory: infra + run: | + npm ci + + pulumi stack select production + + pulumi config set aws:region us-west-2 + pulumi config set domain quadratichq.com + pulumi config set subdomain multiplayer + pulumi config set instanceSize t3.medium + pulumi config set certificate-arn $AWS_PROD_MULTIPLAYER_AMC_ARN + pulumi config set data-dog-env prod + pulumi config set data-dog-api-key ${{ env.DD_API_KEY }} + + pulumi up -y + echo "MULTIPLAYER_INSTANCE_DNS=$(pulumi stack output multiplayerInstanceDns)" >> "$GITHUB_OUTPUT" + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_PROD_MULTIPLAYER_AMC_ARN: ${{ secrets.AWS_PROD_MULTIPLAYER_AMC_ARN }} + PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} + DD_API_KEY: ${{ secrets.DD_API_KEY }} + + outputs: + MULTIPLAYER_INSTANCE_DNS: ${{ steps.pulumiInfra.outputs.MULTIPLAYER_INSTANCE_DNS }} + + + multiplayer_production: + needs: infra + runs-on: ubuntu-latest-8-cores + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Set up Rust + uses: moonrepo/setup-rust@v1 + with: + components: clippy, llvm-tools-preview + cache: false + channel: 'nightly' + + - name: Install pkg-config + if: github.runner.isHosted == true + run: | + sudo apt-get update + sudo apt-get install -y pkg-config + + - name: Build quadratic-multiplayer + working-directory: quadratic-multiplayer + run: | + cargo build --release + + - name: Deploy Multiplayer to EC2 + run: ./infra/multiplayer/deploy-multiplayer-service.sh + env: + EC2_KEY_PEM: ${{ secrets.EC2_KEY_PEM }} + EC2_INSTANCE_DNS: ${{needs.infra.outputs.MULTIPLAYER_INSTANCE_DNS}} \ No newline at end of file diff --git a/.github/workflows/unused/preview-branches.yml b/.github/workflows/unused/preview-branches.yml deleted file mode 100644 index f1d230166c..0000000000 --- a/.github/workflows/unused/preview-branches.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Deploy Preview Branch - -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} - -on: - pull_request: - -jobs: - build-and-deploy: - runs-on: ubuntu-latest-8-cores - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 18 - - name: Set up Rust - uses: moonrepo/setup-rust@v1 - with: - cache: false - - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: 'latest' - - - name: Install Dependencies - run: | - cd quadratic-client - npm install - - - name: Build - run: | - cd quadratic-client - npm run build:wasm:javascript - npm run build:wasm:types - npm run build - env: - VITE_ENVIRONMENT: preview - VITE_QUADRATIC_API_URL: https://quadratic-api-dev-pr-${{ github.event.pull_request.number }}.herokuapp.com - VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} - VITE_AUTH0_CLIENT_ID: ${{ secrets.VITE_AUTH0_CLIENT_ID }} - VITE_AUTH0_AUDIENCE: ${{ secrets.VITE_AUTH0_AUDIENCE }} - VITE_AUTH0_ISSUER: ${{ secrets.VITE_AUTH0_ISSUER }} - VITE_AUTH0_DOMAIN: ${{ secrets.VITE_AUTH0_DOMAIN }} - - # - name: Deploy to AWS S3 - # run: aws s3 sync dist s3://quadratic-preview-branches --delete - # env: - # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - # - name: Invalidate CloudFront Distribution - # run: aws cloudfront create-invalidation --distribution-id your-distribution-id --paths "/*" - # env: - # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - # - name: Post Deployment URL to PR - # if: github.event_name == 'pull_request' - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # DEPLOY_URL: "https://your-cloudfront-distribution-url.com/prs/${{ github.head_ref }}" - # run: | - # PR_COMMENT="Deployment is ready! 🚀\n\nPreview: $DEPLOY_URL" - # PAYLOAD=$(echo '{}' | jq --arg body "$PR_COMMENT" '.body = $body') - # COMMENTS_URL=$(jq -r .pull_request.comments_url < "$GITHUB_EVENT_PATH") - # curl -s -S -H "Authorization: token $GITHUB_TOKEN" -H "Content-Type: application/json" --data "$PAYLOAD" "$COMMENTS_URL" diff --git a/.gitignore b/.gitignore index 55b39173a2..8417997c8e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ node_modules # production /build +quadratic-shared/*.js # misc .DS_Store @@ -34,6 +35,7 @@ venv/* .env.local # Generated Rust files +/target quadratic-core/target/ quadratic-core/tmp.txt quadratic-multiplayer/target/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 95498db3b8..df6b24b72a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,14 +24,12 @@ "Signin", "smallpop", "Southborough", - "subquadrant", - "subquadrants", "unspill", "vals", "Westborough" ], "editor.codeActionsOnSave": { - "source.organizeImports": true + "source.organizeImports": "explicit" }, "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer" diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000..792a95129d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3070 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "ansi-str" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cf4578926a981ab0ca955dc023541d19de37112bc24c1a197bd806d3d86ad1d" +dependencies = [ + "ansitok", +] + +[[package]] +name = "ansitok" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220044e6a1bb31ddee4e3db724d29767f352de47445a6cd75e1a173142136c83" +dependencies = [ + "nom", + "vte", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" +dependencies = [ + "async-trait", + "axum-core", + "base64", + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.0.1", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77cb22c689c44d4c07b0ab44ebc25d69d8ae601a2f28fb8d672d344178fa17aa" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-extra" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523ae92256049a3b02d3bb4df80152386cd97ddba0c8c5077619bdc8c4b1859b" +dependencies = [ + "axum", + "axum-core", + "bytes", + "futures-util", + "headers", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bigdecimal" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06619be423ea5bb86c95f087d5707942791a08a85530df0db2209a3ecfb8bc9" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytecount" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.48.5", +] + +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags 1.3.2", + "clap_lex", + "indexmap 1.9.3", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.70", + "quote 1.0.33", + "strsim", + "syn 2.0.40", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + +[[package]] +name = "deranged" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "deunicode" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "dummy" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e57e12b69e57fad516e01e2b3960f122696fdb13420e1a88ed8e210316f2876" +dependencies = [ + "darling", + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "envy" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965" +dependencies = [ + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fake" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26221445034074d46b276e13eb97a265ebdb8ed8da705c4dddd3dd20b66b45d2" +dependencies = [ + "deunicode", + "dummy", + "rand", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "h2" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.11", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 1.0.0", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64", + "bytes", + "headers-core", + "http 1.0.0", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http 1.0.0", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.11", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.0.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ce4ef31cda248bbdb6e6820603b82dfcd9e833db65a43e997a0ccec777d11fe" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.22", + "http 0.2.11", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.0", + "http 1.0.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.27", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "hyper 1.0.1", + "pin-project-lite", + "socket2 0.5.5", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" +dependencies = [ + "base64", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lexicon_fractional_index" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b14c52534dd690e23b687bdbbbe300d7ec5c45f25e9261f72b70751af67067d3" + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "mockall" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a978c8292954bcb9347a4e28772c0a0621166a1598fc1be28ac0076a4bb810e" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2765371d0978ba4ace4ebef047baa62fc068b431e468444b5610dd441c639b" +dependencies = [ + "cfg-if", + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.3", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "openssl" +version = "0.10.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "papergrid" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ccbe15f2b6db62f9a9871642746427e297b0ceb85f9a7f1ee5ff47d184d0c8" +dependencies = [ + "ansi-str", + "ansitok", + "bytecount", + "fnv", + "unicode-width", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "pem" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923" +dependencies = [ + "base64", + "serde", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "pollster" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "predicates" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" +dependencies = [ + "anstyle", + "itertools 0.11.0", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "proc-macro2" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.4.1", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "proptest-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b46295382dc76166cb7cf2bb4a97952464e4b7ed5a43e6cd34e1fec3349ddc" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "quadratic-core" +version = "0.1.14" +dependencies = [ + "anyhow", + "async-trait", + "bigdecimal", + "chrono", + "console_error_panic_hook", + "criterion", + "csv", + "futures", + "getrandom", + "htmlescape", + "indexmap 2.1.0", + "itertools 0.10.5", + "js-sys", + "lazy_static", + "lexicon_fractional_index", + "pollster", + "proptest", + "proptest-derive", + "rand", + "regex", + "serde", + "serde-wasm-bindgen", + "serde_json", + "serde_repr", + "smallvec", + "strum", + "strum_macros", + "tabled", + "tokio-test", + "ts-rs", + "uuid", + "wasm-bindgen", + "wasm-bindgen-futures", +] + +[[package]] +name = "quadratic-multiplayer" +version = "0.1.0" +dependencies = [ + "anyhow", + "axum", + "axum-extra", + "chrono", + "dotenv", + "envy", + "fake", + "futures", + "futures-util", + "headers", + "jsonwebtoken", + "mockall", + "quadratic-core", + "reqwest", + "rust-shared", + "serde", + "serde_json", + "tokio", + "tokio-tungstenite", + "tower", + "tower-http", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2 1.0.70", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.22", + "http 0.2.11", + "http-body 0.4.6", + "hyper 0.14.27", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.48.0", +] + +[[package]] +name = "rust-shared" +version = "0.1.0" +dependencies = [ + "quadratic-core", + "tabled", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b713f70513ae1f8d92665bbbbda5c295c2cf1da5542881ae5eefe20c9af132" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2 1.0.70", + "quote 1.0.33", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tabled" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfe9c3632da101aba5131ed63f9eed38665f8b3c68703a6bb18124835c1a5d22" +dependencies = [ + "ansi-str", + "ansitok", + "papergrid", + "tabled_derive", + "unicode-width", +] + +[[package]] +name = "tabled_derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.5", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-test" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89b3cbabd3ae862100094ae433e1def582cf86451b4e9bf83aa7ac1d8a7d719" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e12e6351354851911bdf8c2b8f2ab15050c567d70a8b9a37ae7b8301a4080d" +dependencies = [ + "bitflags 2.4.1", + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ts-rs" +version = "7.0.0" +source = "git+https://github.com/HactarCE/ts-rs/?rev=812c1a8#812c1a8b5ff3128916426e95e228f51430eb02cc" +dependencies = [ + "smallvec", + "thiserror", + "ts-rs-macros", + "uuid", +] + +[[package]] +name = "ts-rs-macros" +version = "7.0.0" +source = "git+https://github.com/HactarCE/ts-rs/?rev=812c1a8#812c1a8b5ff3128916426e95e228f51430eb02cc" +dependencies = [ + "Inflector", + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", + "termcolor", +] + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 0.2.11", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", +] + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote 1.0.33", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2 1.0.70", + "quote 1.0.33", + "syn 2.0.40", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..ab74461e00 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[workspace] +resolver = "2" + +members = [ + "quadratic-core", + "quadratic-multiplayer", + "rust-shared", +] + +[workspace.package] +authors = ["Quadratic"] +edition = "2021" +description = "Infinite data grid with Python, JavaScript, and SQL built-in" +repository = "https://github.com/quadratichq/quadratic" +license-file = "LICENSE" diff --git a/Procfile b/Procfile index 38365ab016..0a978143e5 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,3 @@ -web: node -r newrelic quadratic-api/dist/server.js +web: cd quadratic-api && node -r newrelic dist/server.js -release: npx prisma migrate deploy +release: cd quadratic-api && npx prisma migrate deploy diff --git a/amplify.yml b/amplify.yml index 081cf7d778..714ae66792 100644 --- a/amplify.yml +++ b/amplify.yml @@ -1,23 +1,15 @@ version: 1 frontend: phases: - preBuild: - commands: - - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - - source "$HOME/.cargo/env" - - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - - cd quadratic-client - - npm install - build: commands: - - npm run build:wasm:javascript - - npm run build:wasm:types - - npm run build + - ./infra/client/build-client-ci.sh artifacts: baseDirectory: build files: - '**/*' cache: paths: + - node_modules/**/* - quadratic-client/node_modules/**/* + - quadratic-core/target/**/* diff --git a/infra/.gitignore b/infra/.gitignore new file mode 100644 index 0000000000..c6958891dd --- /dev/null +++ b/infra/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/node_modules/ diff --git a/infra/Pulumi.preview.yaml b/infra/Pulumi.preview.yaml new file mode 100644 index 0000000000..5a4036573c --- /dev/null +++ b/infra/Pulumi.preview.yaml @@ -0,0 +1,3 @@ +config: + aws-native:region: us-west-1 + aws:region: us-west-2 diff --git a/infra/Pulumi.yaml b/infra/Pulumi.yaml new file mode 100644 index 0000000000..935026c762 --- /dev/null +++ b/infra/Pulumi.yaml @@ -0,0 +1,3 @@ +name: quadratic-infra +runtime: nodejs +description: Quadratic Infrastructure diff --git a/scripts/run-ci-build.sh b/infra/client/build-client-ci.sh similarity index 60% rename from scripts/run-ci-build.sh rename to infra/client/build-client-ci.sh index 21a0513109..47d6e0fc36 100755 --- a/scripts/run-ci-build.sh +++ b/infra/client/build-client-ci.sh @@ -1,8 +1,15 @@ + +# Setting env vars this way will only work on Vercel +# AWS_PULL_REQUEST_ID is set on Amplify if [ "$VERCEL_ENV" == "preview" ]; then export VITE_QUADRATIC_API_URL="https://quadratic-api-dev-pr-$VERCEL_GIT_PULL_REQUEST_ID.herokuapp.com" echo "On preview branch. Setting VITE_QUADRATIC_API_URL to quadratic-api-dev-pr-$VERCEL_GIT_PULL_REQUEST_ID.herokuapp.com" + export VITE_QUADRATIC_MULTIPLAYER_URL="wss://multiplayer-pr-$VERCEL_GIT_PULL_REQUEST_ID.quadratic-preview.com/ws" + echo "On preview branch. Setting VITE_QUADRATIC_MULTIPLAYER_URL to wss://multiplayer-pr-$VERCEL_GIT_PULL_REQUEST_ID.quadratic-preview.com/ws" fi +# These commands are used in production on AWS Amplify + echo 'Installing rustup...' curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y source "$HOME/.cargo/env" @@ -19,4 +26,5 @@ echo 'Exporting TS/Rust types...' cargo run --bin export_types echo 'Building front-end...' -npm run build --workspace=quadratic-client \ No newline at end of file +npm ci +npm run build --workspace=quadratic-client diff --git a/infra/index.ts b/infra/index.ts new file mode 100644 index 0000000000..58f3dbbffb --- /dev/null +++ b/infra/index.ts @@ -0,0 +1,10 @@ +// This file is the entry point for the infra package. + +// Infra stack for the multiplayer service. +import { + multiplayerInstanceDns, + multiplayerPublicDns, +} from "./multiplayer/multiplayer"; + +// Global exports +export { multiplayerInstanceDns, multiplayerPublicDns }; diff --git a/infra/multiplayer/deploy-multiplayer-service.sh b/infra/multiplayer/deploy-multiplayer-service.sh new file mode 100755 index 0000000000..43e4a3660f --- /dev/null +++ b/infra/multiplayer/deploy-multiplayer-service.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +echo 'Setting Up SSH Key' +mkdir -p ~/.ssh +echo "$EC2_KEY_PEM" > ~/.ssh/id_rsa +chmod 600 ~/.ssh/id_rsa + + +echo 'Wait for EC2 Availability' +timeout=300 # 5 minutes +elapsed=0 +echo "Checking EC2 instance availability..." +while ! ssh -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa ubuntu@$EC2_INSTANCE_DNS "echo 'EC2 instance is up and running'" && [ $elapsed -lt $timeout ]; do + echo "Waiting for EC2 instance to be available..." + sleep 10 + elapsed=$((elapsed + 10)) +done +if [ $elapsed -ge $timeout ]; then + echo "Timeout waiting for EC2 instance to become available" + exit 1 +fi +echo "EC2 instance is available" + + + +echo 'Stop Service on EC2' +ssh -i ~/.ssh/id_rsa ubuntu@$EC2_INSTANCE_DNS "sudo systemctl stop quadratic-multiplayer && rm -f /home/ubuntu/quadratic-multiplayer" + +echo 'Transfer Build to EC2' +scp -i ~/.ssh/id_rsa quadratic-multiplayer/target/release/quadratic-multiplayer ubuntu@$EC2_INSTANCE_DNS:/home/ubuntu/ + +echo 'Restart Service on EC2' +ssh -i ~/.ssh/id_rsa ubuntu@$EC2_INSTANCE_DNS "sudo systemctl start quadratic-multiplayer" + +echo 'Verify Service is running on EC2' +ssh -i ~/.ssh/id_rsa ubuntu@$EC2_INSTANCE_DNS "sudo systemctl is-active --quiet quadratic-multiplayer" \ No newline at end of file diff --git a/infra/multiplayer/multiplayer.ts b/infra/multiplayer/multiplayer.ts new file mode 100644 index 0000000000..9a735effac --- /dev/null +++ b/infra/multiplayer/multiplayer.ts @@ -0,0 +1,124 @@ +import * as aws from "@pulumi/aws"; +import * as pulumi from "@pulumi/pulumi"; +import * as fs from "fs"; +const config = new pulumi.Config(); + +// Configuration +const domain = config.get("domain") || "quadratic-preview.com"; // ex quadratic-preview.com +const multiplayerSubdomain = config.get("subdomain") || "wss-2"; // ex ws +const certificateArn = + config.get("certificate-arn") || + "arn:aws:acm:us-west-2:896845383385:certificate/00300c0e-4243-4296-87c1-83e86bb73a1f"; // ARN of the SSL certificate for quadratic-preview.com (us-west-2) +const instanceSize = config.get("instance-size") || "t2.micro"; +const instanceKeyName = config.get("instance-key-name") || "test2"; +const instanceAmi = config.get("instance-ami") || "ami-0efcece6bed30fd98"; // ubuntu 20.04 LTS +const subNet1 = config.get("subnet1") || "subnet-0ae50871c8ec4e68f"; +const subNet2 = config.get("subnet2") || "subnet-0c6f318928373a253"; +const vpcId = config.get("vpc-id") || "vpc-035fff213c528dbe5"; +const dataDogEnv = config.get("data-dog-env") || "preview"; +const dataDogApiKey = config.get("data-dog-api-key") || ""; + +// Infrastructure +const group = new aws.ec2.SecurityGroup("multiplayer-sc", { + ingress: [ + { protocol: "tcp", fromPort: 22, toPort: 22, cidrBlocks: ["0.0.0.0/0"] }, + { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] }, + ], + egress: [ + { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] }, + { protocol: "tcp", fromPort: 443, toPort: 443, cidrBlocks: ["0.0.0.0/0"] }, + ], +}); + +// Read the content of the Bash script +let setupMultiplayerService = fs.readFileSync( + "multiplayer/setup-multiplayer-service.sh", + "utf-8" +); +// Set the environment variables in the Bash script +setupMultiplayerService = setupMultiplayerService.replace( + "{{DD_ENV}}", + dataDogEnv +); +setupMultiplayerService = setupMultiplayerService.replace( + "{{DD_API_KEY}}", + dataDogApiKey +); +const instance = new aws.ec2.Instance("multiplayer-instance", { + tags: { + Name: `multiplayer-instance-${multiplayerSubdomain}`, + }, + instanceType: instanceSize, + vpcSecurityGroupIds: [group.id], + ami: instanceAmi, + keyName: instanceKeyName, + // Run Setup script on instance boot to create multiplayer systemd service + userData: setupMultiplayerService, +}); + +// Create a new Network Load Balancer +const nlb = new aws.lb.LoadBalancer("multiplayer-nlb", { + internal: false, + loadBalancerType: "network", + subnets: [subNet1, subNet2], + enableCrossZoneLoadBalancing: true, +}); + +// Create a new Target Group +const targetGroup = new aws.lb.TargetGroup("multiplayer-nlb-tg", { + port: 80, + protocol: "TCP", + targetType: "instance", + vpcId: vpcId, +}); + +// Attach the instance to the new Target Group +const targetGroupAttachment = new aws.lb.TargetGroupAttachment( + "multiplayer-attach-instance-tg", + { + targetId: instance.id, + targetGroupArn: targetGroup.arn, + } +); + +// Create NLB Listener for TLS on port 443 +const nlbListener = new aws.lb.Listener("multiplayer-nlb-listener", { + loadBalancerArn: nlb.arn, + port: 443, + protocol: "TLS", + certificateArn: certificateArn, // Attach the SSL certificate + sslPolicy: "ELBSecurityPolicy-2016-08", // Choose an appropriate SSL policy + defaultActions: [ + { + type: "forward", + targetGroupArn: targetGroup.arn, + }, + ], +}); + +// Get the hosted zone ID for domain +const hostedZone = pulumi.output( + aws.route53.getZone( + { + name: domain, + }, + { async: true } + ) +); + +// Create a Route 53 record pointing to the NLB +const dnsRecord = new aws.route53.Record("multiplayer-r53-record", { + zoneId: hostedZone.id, + name: `${multiplayerSubdomain}.${domain}`, // subdomain you want to use + type: "A", + aliases: [ + { + name: nlb.dnsName, + zoneId: nlb.zoneId, + evaluateTargetHealth: true, + }, + ], +}); + +export const multiplayerInstanceDns = instance.publicDns; +export const multiplayerPublicDns = dnsRecord.name; diff --git a/infra/multiplayer/setup-multiplayer-service.sh b/infra/multiplayer/setup-multiplayer-service.sh new file mode 100644 index 0000000000..c99b442680 --- /dev/null +++ b/infra/multiplayer/setup-multiplayer-service.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# Create a systemd service +cat <=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", + "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@logdna/tail-file": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@logdna/tail-file/-/tail-file-2.2.0.tgz", + "integrity": "sha512-XGSsWDweP80Fks16lwkAUIr54ICyBs6PsI4mpfTLQaWgEJRtY9xEV+PeyDpJ+sJEGZxqINlpmAwe/6tS1pP8Ng==", + "engines": { + "node": ">=10.3.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", + "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-metrics": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-metrics/-/api-metrics-0.32.0.tgz", + "integrity": "sha512-g1WLhpG8B6iuDyZJFRGsR+JKyZ94m5LEmY2f+duEJ9Xb4XRlLHrZvh6G34OH6GJ8iDHxfHb/sWjJ1ZpkI9yGMQ==", + "deprecated": "Please use @opentelemetry/api >= 1.3.0", + "dependencies": { + "@opentelemetry/api": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.18.1.tgz", + "integrity": "sha512-HHfJR32NH2x0b69CACCwH8m1dpNALoCTtpgmIWMNkeMGNUeKT48d4AX4xsF4uIRuUoRTbTgtSBRvS+cF97qwCQ==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.18.1.tgz", + "integrity": "sha512-kvnUqezHMhsQvdsnhnqTNfAJs3ox/isB0SVrM1dhVFw7SsB7TstuVa6fgWnN2GdPyilIFLUvvbTZoVRmx6eiRg==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.18.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.18.1.tgz", + "integrity": "sha512-RmoWVFXFhvIh3q4szUe8I+/vxuMR0HNsOm39zNxnWJcK7JDwnPra9cLY/M78u6bTgB6Fte8GKgU128vvDzz0Iw==", + "dependencies": { + "@opentelemetry/core": "1.18.1", + "@opentelemetry/resources": "1.18.1", + "@opentelemetry/sdk-trace-base": "1.18.1", + "@opentelemetry/semantic-conventions": "1.18.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.32.0.tgz", + "integrity": "sha512-y6ADjHpkUz/v1nkyyYjsQa/zorhX+0qVGpFvXMcbjU4sHnBnC02c6wcc93sIgZfiQClIWo45TGku1KQxJ5UUbQ==", + "dependencies": { + "@opentelemetry/api-metrics": "0.32.0", + "require-in-the-middle": "^5.0.3", + "semver": "^7.3.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation-grpc": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.32.0.tgz", + "integrity": "sha512-Az6wdkPx/Mi26lT9LKFV6GhCA9prwQFPz5eCNSExTnSP49YhQ7XCjzPd2POPeLKt84ICitrBMdE1mj0zbPdLAQ==", + "dependencies": { + "@opentelemetry/api-metrics": "0.32.0", + "@opentelemetry/instrumentation": "0.32.0", + "@opentelemetry/semantic-conventions": "1.6.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation-grpc/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.6.0.tgz", + "integrity": "sha512-aPfcBeLErM/PPiAuAbNFLN5sNbZLc3KZlar27uohllN8Zs6jJbHyJU1y7cMA6W/zuq+thkaG8mujiS+3iD/FWQ==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.18.1.tgz", + "integrity": "sha512-oSTUOsnt31JDx5SoEy27B5jE1/tiPvvE46w7CDKj0R5oZhCCfYH2bbSGa7NOOyDXDNqQDkgqU1DIV/xOd3f8pw==", + "dependencies": { + "@opentelemetry/core": "1.18.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.18.1.tgz", + "integrity": "sha512-Kh4M1Qewv0Tbmts6D8LgNzx99IjdE18LCmY/utMkgVyU7Bg31Yuj+X6ZyoIRKPcD2EV4rVkuRI16WVMRuGbhWA==", + "dependencies": { + "@opentelemetry/core": "1.18.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.18.1.tgz", + "integrity": "sha512-JjbcQLYMttXcIabflLRuaw5oof5gToYV9fuXbcsoOeQ0BlbwUn6DAZi++PNsSz2jjPeASfDls10iaO/8BRIPRA==", + "dependencies": { + "@opentelemetry/core": "1.18.1", + "@opentelemetry/semantic-conventions": "1.18.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.18.1.tgz", + "integrity": "sha512-tRHfDxN5dO+nop78EWJpzZwHsN1ewrZRVVwo03VJa3JQZxToRDH29/+MB24+yoa+IArerdr7INFJiX/iN4gjqg==", + "dependencies": { + "@opentelemetry/core": "1.18.1", + "@opentelemetry/resources": "1.18.1", + "@opentelemetry/semantic-conventions": "1.18.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.18.1.tgz", + "integrity": "sha512-ML0l9TNlfLoplLF1F8lb95NGKgdm6OezDS3Ymqav9sYxMd5bnH2LZVzd4xEF+ov5vpZJOGdWxJMs2nC9no7+xA==", + "dependencies": { + "@opentelemetry/context-async-hooks": "1.18.1", + "@opentelemetry/core": "1.18.1", + "@opentelemetry/propagator-b3": "1.18.1", + "@opentelemetry/propagator-jaeger": "1.18.1", + "@opentelemetry/sdk-trace-base": "1.18.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.8.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.18.1.tgz", + "integrity": "sha512-+NLGHr6VZwcgE/2lw8zDIufOCGnzsA5CbQIMleXZTrgkBd0TanCX+MiDYJ1TOS4KL/Tqk0nFRxawnaYr6pkZkA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@pulumi/aws": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@pulumi/aws/-/aws-6.13.1.tgz", + "integrity": "sha512-/yrcZVaYx45gaaQe8X4iPA368ZNk8WbETJ4BwUzcDK9Om36o4Meqfh7JTGpruAgu4LmQLwiMYj8Bznk7lbtbmA==", + "dependencies": { + "@pulumi/pulumi": "^3.0.0", + "builtin-modules": "3.0.0", + "mime": "^2.0.0", + "read-package-tree": "^5.2.1", + "resolve": "^1.7.1" + } + }, + "node_modules/@pulumi/command": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@pulumi/command/-/command-0.9.2.tgz", + "integrity": "sha512-9RaGDiy8jFCiaarj4EOrMW/fVCM/AgBigzwM6CKzlR49x8UFiRDmKrXfEVHb8r2P9IpC4IaAZf5VbNNAHwN/rA==", + "hasInstallScript": true, + "dependencies": { + "@pulumi/pulumi": "^3.0.0" + } + }, + "node_modules/@pulumi/pulumi": { + "version": "3.96.1", + "resolved": "https://registry.npmjs.org/@pulumi/pulumi/-/pulumi-3.96.1.tgz", + "integrity": "sha512-/aHAYT1jWzJA6DNVsFuinSJ+b1w1jLpFBq1KlNKz1rszeSqreP6w4dylXKCZSTdtX1JM/1iEghFGo/rB5ygI6w==", + "dependencies": { + "@grpc/grpc-js": "1.9.6", + "@logdna/tail-file": "^2.0.6", + "@opentelemetry/api": "^1.2.0", + "@opentelemetry/exporter-zipkin": "^1.6.0", + "@opentelemetry/instrumentation": "^0.32.0", + "@opentelemetry/instrumentation-grpc": "^0.32.0", + "@opentelemetry/resources": "^1.6.0", + "@opentelemetry/sdk-trace-base": "^1.6.0", + "@opentelemetry/sdk-trace-node": "^1.6.0", + "@opentelemetry/semantic-conventions": "^1.6.0", + "@pulumi/query": "^0.3.0", + "@types/google-protobuf": "^3.15.5", + "execa": "^5.1.0", + "google-protobuf": "^3.5.0", + "ini": "^2.0.0", + "js-yaml": "^3.14.0", + "minimist": "^1.2.6", + "normalize-package-data": "^3.0.0", + "pkg-dir": "^7.0.0", + "read-package-tree": "^5.3.1", + "require-from-string": "^2.0.1", + "semver": "^7.5.2", + "source-map-support": "^0.5.6", + "ts-node": "^7.0.1", + "typescript": "~3.8.3", + "upath": "^1.1.0" + }, + "engines": { + "node": ">=8.13.0 || >=10.10.0" + } + }, + "node_modules/@pulumi/query": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@pulumi/query/-/query-0.3.0.tgz", + "integrity": "sha512-xfo+yLRM2zVjVEA4p23IjQWzyWl1ZhWOGobsBqRpIarzLvwNH/RAGaoehdxlhx4X92302DrpdIFgTICMN4P38w==" + }, + "node_modules/@types/google-protobuf": { + "version": "3.15.12", + "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.12.tgz", + "integrity": "sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==" + }, + "node_modules/@types/node": { + "version": "18.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", + "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz", + "integrity": "sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builtin-modules": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.0.0.tgz", + "integrity": "sha512-hMIeU4K2ilbXV6Uv93ZZ0Avg/M91RaKXucQ+4me2Do1txxBDyDZWCBa5bJSLqoNTRpXTLwEzIk1KmloenDDjhg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "engines": { + "node": "*" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/google-protobuf": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", + "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.7.tgz", + "integrity": "sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==", + "dependencies": { + "array.prototype.reduce": "^1.0.6", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "safe-array-concat": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/read-package-json": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", + "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "node_modules/read-package-json/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-package-json/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "deprecated": "The functionality that this package provided is now in @npmcli/arborist", + "dependencies": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz", + "integrity": "sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==", + "dependencies": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha512-K+5eQPYs14b3+E+hmE2J6gCZ4JmMl9DbYS6BeP2CHq6WMuNxErxf5B/n0fz85L8zUuoO6rIzNNmIQDu/j+1OcA==", + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/infra/package.json b/infra/package.json new file mode 100644 index 0000000000..e6f7038a66 --- /dev/null +++ b/infra/package.json @@ -0,0 +1,12 @@ +{ + "name": "quadratic-infra", + "main": "index.ts", + "devDependencies": { + "@types/node": "^18" + }, + "dependencies": { + "@pulumi/aws": "^6.13.1", + "@pulumi/command": "^0.9.2", + "@pulumi/pulumi": "^3.0.0" + } +} diff --git a/infra/tsconfig.json b/infra/tsconfig.json new file mode 100644 index 0000000000..ab65afa613 --- /dev/null +++ b/infra/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "strict": true, + "outDir": "bin", + "target": "es2016", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.ts" + ] +} diff --git a/package-lock.json b/package-lock.json index a43ae2758c..9b9fc199f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,9 @@ "prettier": "2.8.3", "ts-jest": "^29.1.1", "typescript": "^5.3.2" + }, + "engines": { + "node": "18.x" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -8666,6 +8669,11 @@ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" }, + "node_modules/@types/ua-parser-js": { + "version": "0.7.39", + "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.39.tgz", + "integrity": "sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==" + }, "node_modules/@types/uuid": { "version": "9.0.7", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", @@ -21823,6 +21831,7 @@ "@sentry/react": "^7.76.0", "@szhsin/react-menu": "^4.0.2", "@types/react-avatar-editor": "^13.0.2", + "@types/ua-parser-js": "^0.7.39", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "color": "^4.2.3", @@ -21841,8 +21850,10 @@ "react-hook-form": "^7.48.2", "react-router-dom": "^6.19.0", "recoil": "^0.7.7", + "semver": "^7.5.4", "tailwind-merge": "^2.0.0", "tailwindcss-animate": "^1.0.7", + "ua-parser-js": "^1.0.37", "uuid": "^9.0.0" }, "devDependencies": { @@ -21878,6 +21889,17 @@ "node": ">=18.0.0" } }, + "quadratic-client/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "quadratic-client/node_modules/prettier-plugin-tailwindcss": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.4.1.tgz", @@ -21952,6 +21974,25 @@ } } }, + "quadratic-client/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "quadratic-client/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "quadratic-multiplayer": { "version": "0.1.0", "devDependencies": {} diff --git a/package.json b/package.json index 745fef2be3..35a262554f 100644 --- a/package.json +++ b/package.json @@ -16,16 +16,15 @@ ], "scripts": { "start": "npm run watch:front-end", - "start:api": "npm start --workspace=quadratic-api", + "api:start": "npm start --workspace=quadratic-api", "perf": "npm run watch:perf:front-end", "watch:javascript": "cd quadratic-client && npm run watch:javascript", - "watch:front-end-back-end": "npm run build:wasm:types && concurrently -n=react,rust,api \"npm:watch:javascript\" \"npm:watch:wasm:javascript\" \"npm:start:api\" \"npm:watch:multiplayer\"", + "watch:front-end": "npm run build:wasm:types && concurrently -n=react,core,api,multiplayer \"npm:watch:javascript\" \"npm:watch:wasm:javascript\" \"npm:api:start\" \"npm:watch:multiplayer\"", + "watch:perf:front-end": "npm run build:wasm:types && concurrently -n=react,rust,api \"npm:watch:javascript\" \"npm:watch:wasm:perf:javascript\" \"npm run api:start\"", + "watch:front-end-back-end": "npm run build:wasm:types && concurrently -n=react,core,api,multiplayer \"npm:watch:javascript\" \"npm:watch:wasm:javascript\" \"npm:start:api\" \"npm:watch:multiplayer\"", "watch:app": "npm run build:wasm:types && concurrently -n=react,api 'npm:watch:javascript' 'npm run start:api'", "watch:multiplayer": "npm run dev --workspace=quadratic-multiplayer", "lint:client": "cd quadratic-client && npm run lint:ts && npm run lint:eslint && lint:prettier && lint:clippy", - "watch:perf:front-end": "npm run build:wasm:types && concurrently -n=react,rust,api \"npm:watch:javascript\" \"npm:watch:wasm:perf:javascript\" \"npm run api:start\"", - "watch:front-end": "npm run build:wasm:types && concurrently -n=react,rust,api \"npm:watch:javascript\" \"npm:watch:wasm:javascript\" \"npm run api:start\"", - "api:start": "cd quadratic-api && npm start", "build:wasm:types": "cd quadratic-core && cargo run --bin export_types", "watch:wasm:javascript": "cd quadratic-core && cargo watch -s 'wasm-pack build --dev --target web --out-dir ../quadratic-client/src/quadratic-core --weak-refs'", "watch:wasm:perf:javascript": "cd quadratic-core && cargo watch -s 'wasm-pack build --target web --out-dir ../quadratic-client/src/quadratic-core --weak-refs'", @@ -33,12 +32,12 @@ "coverage:wasm:gen": "cd quadratic-core && cd quadratic-core && CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' LLVM_PROFILE_FILE='coverage/cargo-test-%p-%m.profraw' cargo test", "coverage:wasm:html": "cd quadratic-core && cd quadratic-core && grcov . --binary-path ./target/debug/deps/ -s . -t html --branch --ignore-not-existing --ignore 'src/wasm_bindings/*' --ignore 'src/bin/*' --ignore '../*' --ignore '/*' -o coverage/html", "coverage:wasm:view": "open quadratic-core/coverage/html/index.html", - "test:wasm": "cd run test --workspace=quadratic-core", + "test:wasm": "cd quadratic-core && cargo test", "test:multiplayer": "npm run test --workspace=quadratic-multiplayer", "watch:test:wasm": "cd quadratic-core && cargo watch -x test", "benchmark:rust": "cd quadratic-core && cargo bench", "lint:clippy": "cd quadratic-core && cargo clippy --all-targets --all-features -- -D warnings", - "build": "npm run build --workspace=quadratic-api" + "heroku-postbuild": "npm run build --workspace=quadratic-api" }, "dependencies": { "zod": "^3.22.4" @@ -47,9 +46,12 @@ "@types/jest": "^29.5.3", "concurrently": "^6.5.1", "eslint": "^8.54.0", - "typescript": "^5.3.2", - "prettier": "2.8.3", "jest": "^29.6.1", - "ts-jest": "^29.1.1" + "prettier": "2.8.3", + "ts-jest": "^29.1.1", + "typescript": "^5.3.2" + }, + "engines": { + "node": "18.x" } } diff --git a/quadratic-api/package.json b/quadratic-api/package.json index a3bc36dc7a..093ca9db87 100644 --- a/quadratic-api/package.json +++ b/quadratic-api/package.json @@ -4,10 +4,10 @@ "description": "", "main": "index.js", "scripts": { - "start": "dotenv -e .env -- ts-node-dev --respawn --exit-child --watch src --project ./tsconfig.json -- ./src/server.ts ", + "start": "dotenv -e .env -- ts-node-dev --respawn --exit-child --watch src --project ./tsconfig.json -- ./src/server.ts --max-old-space-size=8192", "postinstall": "prisma generate", "prebuild": "rm -rf dist", - "build": "tsc", + "build": "tsc && tsc ../quadratic-shared/*.ts", "lint": "npm run lint:eslint && npm run lint:prettier", "lint:eslint": "eslint src/**/*.ts", "lint:eslint:write": "eslint src/**/*.ts --fix", diff --git a/quadratic-client/package.json b/quadratic-client/package.json index 848c2ff1d2..989c6f7725 100644 --- a/quadratic-client/package.json +++ b/quadratic-client/package.json @@ -34,6 +34,7 @@ "@sentry/react": "^7.76.0", "@szhsin/react-menu": "^4.0.2", "@types/react-avatar-editor": "^13.0.2", + "@types/ua-parser-js": "^0.7.39", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "color": "^4.2.3", @@ -52,20 +53,22 @@ "react-hook-form": "^7.48.2", "react-router-dom": "^6.19.0", "recoil": "^0.7.7", + "semver": "^7.5.4", "tailwind-merge": "^2.0.0", "tailwindcss-animate": "^1.0.7", + "ua-parser-js": "^1.0.37", "uuid": "^9.0.0" }, "main": "public/electron.js", "scripts": { "start": "npm run watch:fast:front-end", - "build": "export VITE_VERSION=$(git rev-parse HEAD) && vite build", + "build": "export VITE_VERSION=$(git rev-parse HEAD) NODE_OPTIONS=--max-old-space-size=8192 && vite build", "build:wasm": "npm run build:wasm:javascript && npm run build:wasm:nodejs && npm run build:wasm:types", "build:wasm:types": "cd .. && cd quadratic-core && cargo run --bin export_types", "build:wasm:javascript": "cd .. && cd quadratic-core && wasm-pack build --target web --out-dir ../quadratic-client/src/quadratic-core --weak-refs", "build:wasm:nodejs": "cd .. && cd quadratic-core && wasm-pack build --target nodejs --out-dir ../quadratic-client/src/quadratic-core/__mocks__ --weak-refs", "build:wasm:javascript:dev": "cd .. && cd quadratic-core && wasm-pack build --target web --out-dir ../quadratic-client/src/quadratic-core --weak-refs --dev", - "watch:javascript": "export VITE_VERSION=$(git rev-parse HEAD) && vite dev", + "watch:javascript": "export VITE_VERSION=$(git rev-parse HEAD) && export NODE_OPTIONS=--max-old-space-size=8192 && vite dev", "start:production": "npm run build && serve build", "test:all": "concurrently \"npm run test:unit:ci\" \"npm run test:e2e\"", "test:unit": "node --experimental-vm-modules ../node_modules/jest/bin/jest.js", diff --git a/quadratic-client/src/atoms/editorInteractionStateAtom.ts b/quadratic-client/src/atoms/editorInteractionStateAtom.ts index ab67f74635..2020d5dbab 100644 --- a/quadratic-client/src/atoms/editorInteractionStateAtom.ts +++ b/quadratic-client/src/atoms/editorInteractionStateAtom.ts @@ -11,9 +11,11 @@ export interface EditorInteractionState { showFeedbackMenu: boolean; showShareFileMenu: boolean; permission: ApiTypes['/v0/files/:uuid.GET.response']['permission']; + uuid: string; selectedCell: Coordinate; selectedCellSheet: string; mode: CellType; + follow?: string; } export const editorInteractionStateDefault: EditorInteractionState = { @@ -23,7 +25,8 @@ export const editorInteractionStateDefault: EditorInteractionState = { showGoToMenu: false, showFeedbackMenu: false, showShareFileMenu: false, - permission: 'VIEWER', // FYI: when we call we initialize this with the value from the server + permission: 'VIEWER', // when we call we initialize this with the value from the server + uuid: '', // when we call we initialize this with the value from the server selectedCell: { x: 0, y: 0 }, selectedCellSheet: '', mode: 'TEXT', diff --git a/quadratic-client/src/dashboard/FileRoute.tsx b/quadratic-client/src/dashboard/FileRoute.tsx index 74b84c282a..76feaa734c 100644 --- a/quadratic-client/src/dashboard/FileRoute.tsx +++ b/quadratic-client/src/dashboard/FileRoute.tsx @@ -1,7 +1,5 @@ import { ApiError } from '@/api/fetchFromApi'; import { CONTACT_URL } from '@/constants/urls'; -import { multiplayer } from '@/multiplayer/multiplayer'; -import { useRootRouteLoaderData } from '@/router'; import { Button } from '@/shadcn/ui/button'; import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; import * as Sentry from '@sentry/react'; @@ -77,17 +75,16 @@ export const loader = async ({ request, params }: LoaderFunctionArgs): Promise { - const { user } = useRootRouteLoaderData(); - // Initialize recoil with the file's permission we get from the server const { permission, uuid } = useLoaderData() as FileData; const initializeState = ({ set }: MutableSnapshot) => { set(editorInteractionStateAtom, (prevState) => ({ ...prevState, + uuid, permission, })); }; - multiplayer.enterFileRoom(uuid, user); + // multiplayer.enterFileRoom(uuid, user); return ( diff --git a/quadratic-client/src/debugFlags.ts b/quadratic-client/src/debugFlags.ts index b3b471ac54..713ca374bf 100644 --- a/quadratic-client/src/debugFlags.ts +++ b/quadratic-client/src/debugFlags.ts @@ -57,31 +57,6 @@ export const debugShowCellsHashBoxes = (debug && false) || url.has('cell-boxes') // shows CellsHash information export const debugShowCellHashesInfo = debug && false; -// ---------------- -// Quadrant caching -// ---------------- - -// shows information about subquadrant generation -export const debugShowSubCacheInfo = debug && false; - -// always show cache instead of cell rendering -export const debugAlwaysShowCache = debug && false; - -// shows information about quadrant generation -export const debugShowCacheInfo = debug && false; - -// always show cells instead of cache rendering -export const debugNeverShowCache = debug && false; - -// don't render quadrants -export const debugSkipQuadrantRendering = debug && false; - -// show quadrant colored boxes around rendered range -export const debugShowQuadrantBoxes = debug && false; - -// only render getCellsForDirtyQuadrants -- useful for testing the direct draw of multiple dirty quadrants -export const debugShowCellsForDirtyQuadrants = debug && false; - // -------- // Misc. // -------- @@ -90,6 +65,8 @@ export const debugShowFileIO = debug && true; export const debugGridSettings = debug && false; +export const debugShowMultiplayer = debug && true; + // -------- // UI // -------- diff --git a/quadratic-client/src/grid/actions/clearBordersAction.ts b/quadratic-client/src/grid/actions/clearBordersAction.ts deleted file mode 100644 index 4f1ddd1e06..0000000000 --- a/quadratic-client/src/grid/actions/clearBordersAction.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Coordinate } from '../../gridGL/types/size'; - -export const clearBordersAction = (args: { start: Coordinate; end: Coordinate; create_transaction?: boolean }) => { - throw new Error('not implemented'); - // const { start, end, create_transaction } = args; - // const { sheet } = sheetController; - - // // get all borders in the selection - // const borderUpdate: Border[] = []; - // const borderDelete: Coordinate[] = []; - // for (let y = start.y; y <= end.y; y++) { - // for (let x = start.x; x <= end.x; x++) { - // const border = sheet.borders.get(x, y); - // if (border) { - // borderDelete.push({ x, y }); - // } - // if (x === end.x) { - // const border = sheet.borders.get(x + 1, y); - // if (border?.vertical) { - // if (!border.horizontal) { - // borderDelete.push({ x: x + 1, y }); - // } else { - // borderUpdate.push({ ...border, vertical: undefined }); - // } - // } - // } - // if (y === end.y) { - // const border = sheet.borders.get(x, y + 1); - // if (border?.horizontal) { - // if (!border.vertical) { - // borderDelete.push({ x, y: y + 1 }); - // } else { - // borderUpdate.push({ ...border, horizontal: undefined }); - // } - // } - // } - // } - // } - - // // create transaction to update borders - // if (create_transaction ?? true) sheetController.start_transaction(); - - // const borders: (Border | Coordinate)[] = []; - // if (borderDelete.length) { - // borders.push( - // ...borderDelete.map((border) => { - // return { x: border.x, y: border.y }; - // }) - // ); - // } - // if (borderUpdate.length) { - // borders.push(...borderUpdate); - // } - // if (borders.length) { - // sheetController.execute_statement({ - // type: 'SET_BORDERS', - // data: borders, - // }); - // } - // if (create_transaction ?? true) sheetController.end_transaction(); - - // pixiAppEvents.quadrantsChanged({ range: { start, end } }); -}; diff --git a/quadratic-client/src/grid/controller/Grid.ts b/quadratic-client/src/grid/controller/Grid.ts index 4544e5a4f5..c8f13884ef 100644 --- a/quadratic-client/src/grid/controller/Grid.ts +++ b/quadratic-client/src/grid/controller/Grid.ts @@ -1,3 +1,5 @@ +import { htmlCellsHandler } from '@/gridGL/htmlCells/htmlCellsHandler'; +import { multiplayer } from '@/multiplayer/multiplayer'; import * as Sentry from '@sentry/react'; import { Point, Rectangle } from 'pixi.js'; import { debugMockLargeData } from '../../debugFlags'; @@ -105,6 +107,9 @@ export class Grid { if (summary.offsets_modified.length) { sheets.updateOffsets(summary.offsets_modified); pixiApp.cellsSheets.updateBorders(summary.offsets_modified); + htmlCellsHandler.updateOffsets(summary.offsets_modified.map((offset) => offset.id)); + pixiApp.cursor.dirty = true; + pixiApp.multiplayerCursor.dirty = true; } if (summary.code_cells_modified.length) { @@ -136,6 +141,10 @@ export class Grid { this.dirty = true; window.dispatchEvent(new CustomEvent('transaction-complete')); } + + if (summary.forward_operations) { + multiplayer.sendTransaction(summary.forward_operations); + } pixiApp.setViewportDirty(); } @@ -740,6 +749,11 @@ export class Grid { ); } + multiplayerTransaction(transaction: string) { + const summary = this.gridController.multiplayerTransaction(transaction); + this.transactionResponse(summary); + } + //#endregion } diff --git a/quadratic-client/src/grid/controller/Sheets.ts b/quadratic-client/src/grid/controller/Sheets.ts index e27ac27429..2021f05210 100644 --- a/quadratic-client/src/grid/controller/Sheets.ts +++ b/quadratic-client/src/grid/controller/Sheets.ts @@ -90,11 +90,11 @@ class Sheets { pixiApp.axesLines.dirty = true; pixiApp.headings.dirty = true; pixiApp.cursor.dirty = true; - // pixiApp.quadrants.changeSheet(); pixiApp.boxCells.reset(); pixiAppSettings.changeInput(false); pixiApp.cellsSheets.show(sheets.sheet.id); this.updateSheetBar(); + pixiApp.loadViewport(); } } @@ -267,6 +267,10 @@ class Sheets { pixiApp.gridLines.dirty = true; pixiApp.cursor.dirty = true; } + + getMultiplayerSelection(): string { + return this.sheet.cursor.getMultiplayerSelection(); + } } export const sheets = new Sheets(); diff --git a/quadratic-client/src/grid/sheet/GridBorders.ts.tbd b/quadratic-client/src/grid/sheet/GridBorders.ts.tbd deleted file mode 100644 index faf810c98c..0000000000 --- a/quadratic-client/src/grid/sheet/GridBorders.ts.tbd +++ /dev/null @@ -1,141 +0,0 @@ -import { Rectangle } from 'pixi.js'; -import { Quadrants } from '../../gridGL/quadrants/Quadrants'; -import { Coordinate, MinMax } from '../../gridGL/types/size'; -import { Border } from '../../schemas'; -import { Bounds } from './Bounds'; - -export class GridBorders { - private bounds = new Bounds(); - borders = new Map(); - - // tracks which quadrants need to render based on GridBorders data - quadrants: Set = new Set(); - - empty() { - this.borders.clear(); - this.quadrants.clear(); - this.bounds.clear(); - } - - private getKey(x?: number, y?: number): string { - return `${x ?? ''},${y ?? ''}`; - } - - populate(borders?: Border[]) { - this.empty(); - if (!borders?.length) return; - this.borders.clear(); - this.quadrants.clear(); - borders?.forEach((border) => { - this.borders.set(this.getKey(border.x, border.y), border); - this.quadrants.add(Quadrants.getKey(border.x, border.y)); - this.bounds.add(border.x, border.y); - }); - } - - recalculateBounds(): void { - this.bounds.clear(); - if (this.borders.size === 0) return; - this.borders.forEach((border) => { - this.bounds.add(border.x, border.y); - }); - } - - get(x: number, y: number): Border | undefined { - if (this.bounds.contains(x, y)) { - return this.borders.get(this.getKey(x, y)); - } - } - - clear(coordinates: Coordinate[]): void { - coordinates.forEach((coordinate) => this.borders.delete(this.getKey(coordinate.x, coordinate.y))); - this.recalculateBounds(); - } - - update(borders: Border[]): void { - borders.forEach((border) => { - this.borders.set(this.getKey(border.x, border.y), border); - this.quadrants.add(Quadrants.getKey(border.x, border.y)); - this.bounds.add(border.x, border.y); - }); - } - - getBorders(bounds: Rectangle): Border[] { - const borders: Border[] = []; - for (let y = bounds.top; y <= bounds.bottom; y++) { - for (let x = bounds.left; x <= bounds.right; x++) { - if (this.bounds.contains(x, y)) { - const border = this.borders.get(this.getKey(x, y)); - if (border) borders.push(border); - } - } - } - return borders; - } - - getBounds(bounds: Rectangle): Rectangle { - const { minX, minY, maxX, maxY } = this.bounds; - const columnStartIndex = this.gridOffsets.getColumnIndex(bounds.left); - const columnStart = columnStartIndex.index > minX ? columnStartIndex.index : minX; - const columnEndIndex = this.gridOffsets.getColumnIndex(bounds.right); - const columnEnd = columnEndIndex.index < maxX ? columnEndIndex.index : maxX; - - const rowStartIndex = this.gridOffsets.getRowIndex(bounds.top); - const rowStart = rowStartIndex.index > minY ? rowStartIndex.index : minY; - const rowEndIndex = this.gridOffsets.getRowIndex(bounds.bottom); - const rowEnd = rowEndIndex.index < maxY ? rowEndIndex.index : maxY; - - return new Rectangle(columnStart, rowStart, columnEnd - columnStart, rowEnd - rowStart); - } - - getGridBounds(): Rectangle | undefined { - return this.bounds.toRectangle(); - } - - getRowMinMax(row: number): MinMax { - const { minX, maxX } = this.bounds; - let min = Infinity; - let max = -Infinity; - for (let x = minX; x <= maxX; x++) { - if (this.get(x, row)) { - min = x; - break; - } - } - for (let x = maxX; x >= minX; x--) { - if (this.get(x, row)) { - max = x; - break; - } - } - return { min, max }; - } - - getColumnMinMax(column: number): MinMax | undefined { - const { minY, maxY } = this.bounds; - let min = Infinity; - let max = -Infinity; - for (let y = minY; y <= maxY; y++) { - if (this.get(column, y)) { - min = y; - break; - } - } - for (let y = maxY; y >= minY; y--) { - if (this.get(column, y)) { - max = y; - break; - } - } - if (min === Infinity) return; - return { min, max }; - } - - getArray(): Border[] { - return Array.from(this.borders, ([_, border]) => border); - } - - hasQuadrant(x: number, y: number): boolean { - return this.quadrants.has(Quadrants.getKey(x, y)); - } -} diff --git a/quadratic-client/src/grid/sheet/SheetCursor.ts b/quadratic-client/src/grid/sheet/SheetCursor.ts index bf241a8dd5..569e9cb9a2 100644 --- a/quadratic-client/src/grid/sheet/SheetCursor.ts +++ b/quadratic-client/src/grid/sheet/SheetCursor.ts @@ -78,17 +78,21 @@ export class SheetCursor { this.keyboardMovePosition = options.keyboardMovePosition; } pixiApp.updateCursorPosition({ ensureVisible: options.ensureVisible ?? true }); - multiplayer.sendSelection( - this.cursorPosition, - this.multiCursor - ? new Rectangle( - this.multiCursor.originPosition.x, - this.multiCursor.originPosition.y, - this.multiCursor.terminalPosition.x - this.multiCursor.originPosition.x, - this.multiCursor.terminalPosition.y - this.multiCursor.originPosition.y - ) - : undefined - ); + multiplayer.sendSelection(this.getMultiplayerSelection()); + } + + // gets a stringified selection string for multiplayer + getMultiplayerSelection(): string { + const cursor = this.cursorPosition; + const rectangle = this.multiCursor + ? new Rectangle( + this.multiCursor.originPosition.x, + this.multiCursor.originPosition.y, + this.multiCursor.terminalPosition.x - this.multiCursor.originPosition.x, + this.multiCursor.terminalPosition.y - this.multiCursor.originPosition.y + ) + : undefined; + return JSON.stringify({ cursor, rectangle }); } changeBoxCells(boxCells: boolean) { diff --git a/quadratic-client/src/gridGL/QuadraticGrid.tsx b/quadratic-client/src/gridGL/QuadraticGrid.tsx index 20e2a042ab..33eea7cd8d 100644 --- a/quadratic-client/src/gridGL/QuadraticGrid.tsx +++ b/quadratic-client/src/gridGL/QuadraticGrid.tsx @@ -6,6 +6,7 @@ import { FloatingContextMenu } from '../ui/menus/ContextMenu/FloatingContextMenu import { HtmlCells } from './htmlCells/HtmlCells'; import { CellInput } from './interaction/CellInput'; import { useKeyboard } from './interaction/keyboard/useKeyboard'; +import { MultiplayerCellEdits } from './multiplayerInput/MultiplayerCellEdits'; import { pixiApp } from './pixiApp/PixiApp'; import { PanMode, pixiAppSettings } from './pixiApp/PixiAppSettings'; @@ -119,6 +120,7 @@ export default function QuadraticGrid() { onKeyUp={onKeyUp} > {showInput && } + diff --git a/quadratic-client/src/gridGL/UI/Cursor.ts b/quadratic-client/src/gridGL/UI/Cursor.ts index 4c9811e8c1..0a82305239 100644 --- a/quadratic-client/src/gridGL/UI/Cursor.ts +++ b/quadratic-client/src/gridGL/UI/Cursor.ts @@ -17,10 +17,10 @@ const NUM_OF_CELL_REF_COLORS = colors.cellHighlightColor.length; export type CursorCell = { x: number; y: number; width: number; height: number }; const CURSOR_CELL_DEFAULT_VALUE: CursorCell = { x: 0, y: 0, width: 0, height: 0 }; // adds a bit of padding when editing a cell w/CellInput -const CELL_INPUT_PADDING = CURSOR_THICKNESS * 2; +export const CELL_INPUT_PADDING = CURSOR_THICKNESS * 2; // outside border when editing the cell -const INPUT_ALPHA = 0.333; +const CURSOR_INPUT_ALPHA = 0.333; export class Cursor extends Graphics { indicator: Rectangle; @@ -95,7 +95,7 @@ export class Cursor extends Graphics { this.lineStyle({ width: CURSOR_THICKNESS * 1.5, color, - alpha: INPUT_ALPHA, + alpha: CURSOR_INPUT_ALPHA, alignment: 1, }); this.drawRect(x, y, width, height); diff --git a/quadratic-client/src/gridGL/UI/UIMultiplayerCursor.ts b/quadratic-client/src/gridGL/UI/UIMultiplayerCursor.ts index 9e47628274..e4e5319c90 100644 --- a/quadratic-client/src/gridGL/UI/UIMultiplayerCursor.ts +++ b/quadratic-client/src/gridGL/UI/UIMultiplayerCursor.ts @@ -4,11 +4,15 @@ import { Graphics, Rectangle } from 'pixi.js'; import { sheets } from '../../grid/controller/Sheets'; import { pixiApp } from '../pixiApp/PixiApp'; import { Coordinate } from '../types/size'; +import { CELL_INPUT_PADDING } from './Cursor'; export const CURSOR_THICKNESS = 1; const ALPHA = 0.5; const FILL_ALPHA = 0.01 / ALPHA; +// outside border when editing the cell +const CURSOR_INPUT_ALPHA = 0.333 / ALPHA; + export class UIMultiPlayerCursor extends Graphics { dirty = false; @@ -18,23 +22,46 @@ export class UIMultiPlayerCursor extends Graphics { } // todo: handle multiple people in the same cell - private drawCursor(color: number, cursor: Coordinate) { + private drawCursor({ + color, + cursor, + editing, + sessionId, + code, + }: { + color: number; + cursor: Coordinate; + editing: boolean; + sessionId: string; + code: boolean; + }): void { const sheet = sheets.sheet; - + if (cursor.x === undefined || cursor.y === undefined) debugger let { x, y, width, height } = sheet.getCellOffsets(cursor.x, cursor.y); - // draw cursor + if (editing) { + const cellEdit = document.querySelector(`.multiplayer-cell-edit-${sessionId}`) as HTMLDivElement; + if (cellEdit.offsetWidth + CELL_INPUT_PADDING > width) { + width = Math.max(cellEdit.offsetWidth + CELL_INPUT_PADDING, width); + } + } + + // draw cursor) this.lineStyle({ width: CURSOR_THICKNESS, color, alignment: 0, }); - this.moveTo(x, y); - this.lineTo(x + width, y); - this.lineTo(x + width, y + height); - this.moveTo(x + width, y + height); - this.lineTo(x, y + height); - this.lineTo(x, y); + this.drawRect(x, y, width, height); + if (editing || code) { + this.lineStyle({ + width: CURSOR_THICKNESS * 1.5, + color, + alpha: CURSOR_INPUT_ALPHA, + alignment: 1, + }); + this.drawRect(x, y, width, height); + } } private drawMultiCursor(color: number, rectangle: Rectangle): void { @@ -55,15 +82,21 @@ export class UIMultiPlayerCursor extends Graphics { if (this.dirty) { this.dirty = false; this.clear(); - // const sheetId = sheets.sheet.id; - multiplayer.players.forEach((player) => { + const sheetId = sheets.sheet.id; + multiplayer.users.forEach((player) => { const color = MULTIPLAYER_COLORS_TINT[player.color]; - if (player.selection /* && player.sheetId === sheetId */) { - this.drawCursor(color, player.selection.cursor); + if (player.parsedSelection && player.sheet_id === sheetId) { + this.drawCursor({ + color, + cursor: player.parsedSelection.cursor, + editing: player.cell_edit.active, + sessionId: player.session_id, + code: player.cell_edit.code_editor, + }); // note: the rectangle is not really a PIXI.Rectangle, but a (x, y, width, height) type (b/c we JSON stringified) - if (player.selection.rectangle) { - this.drawMultiCursor(color, player.selection.rectangle); + if (player.parsedSelection.rectangle) { + this.drawMultiCursor(color, player.parsedSelection.rectangle); } } }); diff --git a/quadratic-client/src/gridGL/cells/CellsSheets.ts b/quadratic-client/src/gridGL/cells/CellsSheets.ts index b8ddc63c83..d2d122d746 100644 --- a/quadratic-client/src/gridGL/cells/CellsSheets.ts +++ b/quadratic-client/src/gridGL/cells/CellsSheets.ts @@ -31,7 +31,6 @@ export class CellsSheets extends Container { } const cellsSheet = this.addChild(new CellsSheet(sheet)); await cellsSheet.preload(); - this.show(sheet.id); } deleteSheet(id: string): void { @@ -49,7 +48,6 @@ export class CellsSheets extends Container { if (this.current?.sheet.id !== child?.sheet.id) { this.current = child; child.show(pixiApp.viewport.getVisibleBounds()); - pixiApp.loadViewport(); } } else { child.hide(); diff --git a/quadratic-client/src/gridGL/htmlCells/HtmlCell.ts b/quadratic-client/src/gridGL/htmlCells/HtmlCell.ts index 2b340bb8de..80bba00337 100644 --- a/quadratic-client/src/gridGL/htmlCells/HtmlCell.ts +++ b/quadratic-client/src/gridGL/htmlCells/HtmlCell.ts @@ -1,5 +1,6 @@ import { CELL_HEIGHT, CELL_WIDTH } from '@/constants/gridConstants'; import { sheets } from '@/grid/controller/Sheets'; +import { Sheet } from '@/grid/sheet/Sheet'; import { JsHtmlOutput } from '@/quadratic-core/types'; import { colors } from '@/theme/colors'; import { InteractionEvent } from 'pixi.js'; @@ -20,15 +21,22 @@ export class HtmlCell { private resizing: HtmlCellResizing | undefined; private hoverSide: 'right' | 'bottom' | 'corner' | undefined; + sheet: Sheet; + div: HTMLDivElement; constructor(htmlCell: JsHtmlOutput) { this.htmlCell = htmlCell; + const sheet = sheets.getById(htmlCell.sheet_id)!; + if (!sheet) { + throw new Error(`Expected to find sheet with id ${htmlCell.sheet_id}`); + } + this.sheet = sheet; this.div = document.createElement('div'); this.div.className = 'html-cell'; this.div.style.border = `1px solid ${colors.cellColorUserPythonRgba}`; - const offset = sheets.sheet.getCellOffsets(Number(htmlCell.x), Number(htmlCell.y)); + const offset = this.sheet.getCellOffsets(Number(htmlCell.x), Number(htmlCell.y)); // the 0.5 is adjustment for the border this.div.style.left = `${offset.x - 0.5}px`; @@ -57,6 +65,10 @@ export class HtmlCell { } else { this.iframe.addEventListener('load', this.afterLoad); } + + if (this.sheet.id !== sheets.sheet.id) { + this.div.style.visibility = 'hidden'; + } } get x(): number { @@ -253,4 +265,12 @@ export class HtmlCell { setHeight(height: number) { this.iframe.height = height.toString(); } + + updateOffsets() { + const offset = this.sheet.getCellOffsets(this.x, this.y); + + // the 0.5 is adjustment for the border + this.div.style.left = `${offset.x - 0.5}px`; + this.div.style.top = `${offset.y + offset.height - 0.5}px`; + } } diff --git a/quadratic-client/src/gridGL/htmlCells/htmlCellsHandler.ts b/quadratic-client/src/gridGL/htmlCells/htmlCellsHandler.ts index c81204bba1..eac7d4ba2e 100644 --- a/quadratic-client/src/gridGL/htmlCells/htmlCellsHandler.ts +++ b/quadratic-client/src/gridGL/htmlCells/htmlCellsHandler.ts @@ -105,6 +105,13 @@ class HTMLCellsHandler { getCells(): HtmlCell[] { return Array.from(this.cells.values()); } + + // handle changes to offsets + updateOffsets(sheetIds: string[]) { + this.cells.forEach((cell) => { + if (sheetIds.includes(cell.sheet.id)) cell.updateOffsets(); + }); + } } export const htmlCellsHandler = new HTMLCellsHandler(); diff --git a/quadratic-client/src/gridGL/interaction/CellInput.tsx b/quadratic-client/src/gridGL/interaction/CellInput.tsx index 25b66a04e4..4b2034bb0b 100644 --- a/quadratic-client/src/gridGL/interaction/CellInput.tsx +++ b/quadratic-client/src/gridGL/interaction/CellInput.tsx @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ +import { multiplayer } from '@/multiplayer/multiplayer'; import { Rectangle } from 'pixi.js'; import { ClipboardEvent, useCallback, useRef, useState } from 'react'; import { useRecoilState } from 'recoil'; @@ -9,7 +9,7 @@ import { CURSOR_THICKNESS } from '../UI/Cursor'; import { pixiApp } from '../pixiApp/PixiApp'; import { pixiAppSettings } from '../pixiApp/PixiAppSettings'; import { Coordinate } from '../types/size'; -import { isCursorAtEnd, isCursorAtStart } from './contentEditableHelper'; +import { getCursorLocation, isCursorAtEnd, isCursorAtStart } from './contentEditableHelper'; interface CellInputProps { container?: HTMLDivElement; @@ -45,22 +45,32 @@ export const CellInput = (props: CellInputProps) => { } // moves the cursor to the end of the input (since we're placing a single character that caused the input to open) - const handleFocus = useCallback((e: any) => { - const div = e.target; - window.setTimeout(() => { - if (!document.hasFocus() || !div.contains(document.activeElement)) return; - if (div.innerText?.length) { - const selection = document.getSelection(); - const range = document.createRange(); - if (selection) { - range.setStart(div.childNodes[0], div.innerText.length); - range.collapse(true); - selection.removeAllRanges(); - selection.addRange(range); + const handleFocus = useCallback( + (e: any) => { + const div = e.target; + window.setTimeout(() => { + if (!document.hasFocus() || !div.contains(document.activeElement)) return; + if (div.innerText?.length) { + const selection = document.getSelection(); + const range = document.createRange(); + if (selection) { + range.setStart(div.childNodes[0], div.innerText.length); + range.collapse(true); + selection.removeAllRanges(); + selection.addRange(range); + } } - } - }, 0); - }, []); + multiplayer.sendCellEdit( + div.innerText ?? '', + div.innerText?.length ?? 0, + false, + temporaryBold, + temporaryItalic + ); + }, 0); + }, + [temporaryBold, temporaryItalic] + ); // Effect for sizing the input width to the length of the value const [textInput, setTextInput] = useState(); @@ -167,6 +177,9 @@ export const CellInput = (props: CellInputProps) => { const parsed = new DOMParser().parseFromString(text, 'text/html'); const result = parsed.body.textContent || ''; document.execCommand('insertHTML', false, result.replace(/(\r\n|\n|\r)/gm, '')); + if (textInput) { + multiplayer.sendCellEdit(textInput.innerText, getCursorLocation(), false, temporaryBold, temporaryItalic); + } event.preventDefault(); }; @@ -305,6 +318,11 @@ export const CellInput = (props: CellInputProps) => { // ensure the cell border is redrawn pixiApp.cursor.dirty = true; }} + onKeyUp={() => { + if (textInput) { + multiplayer.sendCellEdit(textInput.innerText, getCursorLocation(), false, temporaryBold, temporaryItalic); + } + }} > {text.current} diff --git a/quadratic-client/src/gridGL/interaction/contentEditableHelper.ts b/quadratic-client/src/gridGL/interaction/contentEditableHelper.ts index cc8aa66f9f..e2b8f64eb7 100644 --- a/quadratic-client/src/gridGL/interaction/contentEditableHelper.ts +++ b/quadratic-client/src/gridGL/interaction/contentEditableHelper.ts @@ -11,3 +11,9 @@ export const isCursorAtEnd = (editableDiv: HTMLDivElement): boolean => { if (!selection || selection.rangeCount > 1 || selection.type !== 'Caret') return false; return selection.anchorOffset === editableDiv.textContent?.length; }; + +export const getCursorLocation = (): number => { + const selection = window.getSelection(); + if (!selection || selection.rangeCount > 1 || selection.type !== 'Caret') return 0; + return selection.anchorOffset; +}; diff --git a/quadratic-client/src/gridGL/interaction/pointer/Pointer.ts b/quadratic-client/src/gridGL/interaction/pointer/Pointer.ts index 7e365caf79..b3c2525744 100644 --- a/quadratic-client/src/gridGL/interaction/pointer/Pointer.ts +++ b/quadratic-client/src/gridGL/interaction/pointer/Pointer.ts @@ -6,18 +6,20 @@ import { PointerAutoComplete } from './PointerAutoComplete/PointerAutoComplete'; import { PointerDown } from './PointerDown'; import { PointerHeading } from './PointerHeading'; import { PointerHtmlCells } from './PointerHtmlCells'; +import { PointerCursor } from './pointerCursor'; export class Pointer { pointerHeading: PointerHeading; pointerAutoComplete: PointerAutoComplete; pointerHtmlCells: PointerHtmlCells; - + pointerCursor: PointerCursor; pointerDown: PointerDown; constructor(viewport: Viewport) { this.pointerHeading = new PointerHeading(); this.pointerAutoComplete = new PointerAutoComplete(); this.pointerDown = new PointerDown(); + this.pointerCursor = new PointerCursor(); this.pointerHtmlCells = new PointerHtmlCells(); viewport.on('pointerdown', this.handlePointerDown); @@ -25,6 +27,7 @@ export class Pointer { viewport.on('pointerup', this.pointerUp); viewport.on('pointerupoutside', this.pointerUp); pixiApp.canvas.addEventListener('pointerleave', this.pointerLeave); + window.addEventListener('blur', this.pointerLeave); } private pointerLeave = () => { @@ -38,6 +41,7 @@ export class Pointer { viewport.off('pointerup', this.pointerUp); viewport.off('pointerupoutside', this.pointerUp); pixiApp.canvas.removeEventListener('pointerleave', this.pointerLeave); + window.removeEventListener('blur', this.pointerLeave); this.pointerDown.destroy(); } @@ -62,8 +66,8 @@ export class Pointer { this.pointerHtmlCells.pointerMove(e) || this.pointerHeading.pointerMove(world) || this.pointerAutoComplete.pointerMove(world) || - this.pointerDown.pointerMove(world); - // this.pointerCursor.pointerMove(world); TODO: verify if we need this line + this.pointerDown.pointerMove(world) || + this.pointerCursor.pointerMove(world); // change the cursor based on pointer priority const cursor = diff --git a/quadratic-client/src/gridGL/interaction/pointer/PointerHeading.ts b/quadratic-client/src/gridGL/interaction/pointer/PointerHeading.ts index e732f45598..97ea295a5c 100644 --- a/quadratic-client/src/gridGL/interaction/pointer/PointerHeading.ts +++ b/quadratic-client/src/gridGL/interaction/pointer/PointerHeading.ts @@ -1,3 +1,4 @@ +import { htmlCellsHandler } from '@/gridGL/htmlCells/htmlCellsHandler'; import { InteractivePointerEvent, Point } from 'pixi.js'; import { isEditorOrAbove } from '../../../actions'; import { CELL_TEXT_MARGIN_LEFT, CELL_WIDTH } from '../../../constants/gridConstants'; @@ -181,6 +182,7 @@ export class PointerHeading { column: this.resizing.column, delta: size - this.resizing.lastSize, }); + htmlCellsHandler.updateOffsets([sheets.sheet.id]); this.resizing.lastSize = size; } } else if (this.resizing.row !== undefined) { diff --git a/quadratic-client/src/gridGL/multiplayerInput/MultiplayerCellEdit.tsx b/quadratic-client/src/gridGL/multiplayerInput/MultiplayerCellEdit.tsx new file mode 100644 index 0000000000..77c71cd428 --- /dev/null +++ b/quadratic-client/src/gridGL/multiplayerInput/MultiplayerCellEdit.tsx @@ -0,0 +1,140 @@ +import { useEffect, useRef } from 'react'; +import { sheets } from '../../grid/controller/Sheets'; +import { CURSOR_THICKNESS } from '../UI/Cursor'; +import { pixiApp } from '../pixiApp/PixiApp'; +import { MultiplayerCell } from './useMultiplayerCellEdit'; + +interface Props { + container: HTMLDivElement; + multiplayerCellInput: MultiplayerCell; +} + +const CURSOR_WIDTH = 2; + +export const MultiplayerCellEdit = (props: Props) => { + const { container } = props; + + const { cell, italic, bold, text, cursor, playerColor, sessionId } = props.multiplayerCellInput; + const viewport = pixiApp.viewport; + const sheet = sheets.sheet; + const cellOffsets = sheet.getCellOffsets(cell.x, cell.y); + + const formatting = sheet.getCellFormatSummary(cell.x, cell.y); + const displayItalic = italic === null ? formatting?.italic : italic; + const displayBold = bold === null ? formatting?.bold : bold; + let fontFamily: string = 'OpenSans'; + if (displayItalic && displayBold) { + fontFamily = 'OpenSans-BoldItalic'; + } else if (displayItalic) { + fontFamily = 'OpenSans-Italic'; + } else if (displayBold) { + fontFamily = 'OpenSans-Bold'; + } + + const textInput = useRef(null); + + useEffect(() => { + // Register lister for when grid moves to resize and move input with CSS + viewport.on('moved', updateInputCSSTransform); + viewport.on('moved-end', updateInputCSSTransform); + + return () => { + viewport.off('moved-end', updateInputCSSTransform); + viewport.off('moved', updateInputCSSTransform); + }; + }); + + // If we don't have a viewport, we can't continue. + if (!viewport) return null; + + // Function used to move and scale the Input with the Grid + function updateInputCSSTransform() { + if (!container) return ''; + + // Get world transform matrix + let worldTransform = viewport.worldTransform; + + // Calculate position of input based on cell (magic number via experimentation) + let cell_offset_scaled = viewport.toScreen(cellOffsets.x + CURSOR_THICKNESS, cellOffsets.y + CURSOR_THICKNESS); + + // Generate transform CSS + const transform = + 'matrix(' + + [ + worldTransform.a, + worldTransform.b, + worldTransform.c, + worldTransform.d, + cell_offset_scaled.x + container.offsetLeft, + cell_offset_scaled.y + container.offsetTop, + ].join(',') + + ')'; + + // Update input css matrix + if (textInput.current) textInput.current.style.transform = transform; + + // return transform + return transform; + } + + // set input's initial position correctly + const transform = updateInputCSSTransform(); + + // need to add one extra character at end in case the cursor is there + const textCharacters = text ? [...text.split(''), ''] : []; + + return ( + <> +
+
+ {textCharacters.map((character, index) => { + if (index === cursor) { + return ( + + + {character} + + ); + } else { + return character; + } + })} +
+
+ + ); +}; diff --git a/quadratic-client/src/gridGL/multiplayerInput/MultiplayerCellEdits.tsx b/quadratic-client/src/gridGL/multiplayerInput/MultiplayerCellEdits.tsx new file mode 100644 index 0000000000..c8508e04bb --- /dev/null +++ b/quadratic-client/src/gridGL/multiplayerInput/MultiplayerCellEdits.tsx @@ -0,0 +1,21 @@ +import { MultiplayerCellEdit } from './MultiplayerCellEdit'; +import { useMultiplayerCellEdit } from './useMultiplayerCellEdit'; + +interface Props { + container?: HTMLDivElement; +} + +export const MultiplayerCellEdits = (props: Props) => { + const { container } = props; + const multiplayerCellInput = useMultiplayerCellEdit(); + + if (!container) return; + + return ( +
+ {multiplayerCellInput.map((cell) => ( + + ))} +
+ ); +}; diff --git a/quadratic-client/src/gridGL/multiplayerInput/useMultiplayerCellEdit.tsx b/quadratic-client/src/gridGL/multiplayerInput/useMultiplayerCellEdit.tsx new file mode 100644 index 0000000000..c6335cfcf0 --- /dev/null +++ b/quadratic-client/src/gridGL/multiplayerInput/useMultiplayerCellEdit.tsx @@ -0,0 +1,49 @@ +// Displays when a multiplayer user is editing a cell + +import { sheets } from '@/grid/controller/Sheets'; +import { useEffect, useState } from 'react'; +import { Coordinate } from '../types/size'; + +export interface MultiplayerCell { + sessionId: string; + sheetId: string; + cell: Coordinate; + text?: string; + bold: boolean; + italic: boolean; + cursor: number; + playerColor: string; +} + +export const useMultiplayerCellEdit = (): MultiplayerCell[] => { + const [multiplayerCellInput, setMultiplayerCellInput] = useState([]); + useEffect(() => { + const updateMultiplayerCellEdit = (e: any) => { + const multiplayerCell = e.detail as MultiplayerCell; + setMultiplayerCellInput((prev) => { + const found = prev.findIndex((prev) => prev.sessionId === multiplayerCell.sessionId); + if (multiplayerCell && found === -1) { + return [...prev, multiplayerCell]; + } + return prev.map((cell, index) => { + if (index === found) return multiplayerCell; + return cell; + }); + }); + }; + window.addEventListener('multiplayer-cell-edit', updateMultiplayerCellEdit); + return () => window.removeEventListener('multiplayer-cell-edit', updateMultiplayerCellEdit); + }, []); + + // force rerender when sheet changes + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_, setTrigger] = useState(0); + useEffect(() => { + const updateTrigger = () => setTrigger((prev) => prev + 1); + window.addEventListener('sheet-change', updateTrigger); + return () => window.removeEventListener('sheet-change', updateTrigger); + }); + + // only return users that are actively editing (ie, text !== undefined) + return multiplayerCellInput.filter((cell) => cell.text !== undefined && cell.sheetId === sheets.sheet.id); +}; diff --git a/quadratic-client/src/gridGL/pixiApp/PixiApp.ts b/quadratic-client/src/gridGL/pixiApp/PixiApp.ts index c9d71c38f8..1743128547 100644 --- a/quadratic-client/src/gridGL/pixiApp/PixiApp.ts +++ b/quadratic-client/src/gridGL/pixiApp/PixiApp.ts @@ -1,9 +1,9 @@ +import { multiplayer } from '@/multiplayer/multiplayer'; import { Viewport } from 'pixi-viewport'; -import { Container, Graphics, Rectangle, Renderer } from 'pixi.js'; +import { Container, Graphics, Point, Rectangle, Renderer } from 'pixi.js'; import { isMobile } from 'react-device-detect'; import { editorInteractionStateDefault } from '../../atoms/editorInteractionStateAtom'; import { HEADING_SIZE } from '../../constants/gridConstants'; -import { debugShowCacheFlag } from '../../debugFlags'; import { copyToClipboardEvent, cutToClipboardEvent, @@ -22,16 +22,17 @@ import { Pointer } from '../interaction/pointer/Pointer'; import { ensureVisible } from '../interaction/viewportHelper'; import { loadAssets } from '../loadAssets'; import { HORIZONTAL_SCROLL_KEY, Wheel, ZOOM_KEY } from '../pixiOverride/Wheel'; -import { Quadrants } from '../quadrants/Quadrants'; import { pixiAppSettings } from './PixiAppSettings'; import { Update } from './Update'; import { HighlightedCells } from './highlightedCells'; import './pixiApp.css'; +// todo: move viewport stuff to a viewport.ts file +const MULTIPLAYER_VIEWPORT_EASE_TIME = 100; + export class PixiApp { private parent?: HTMLDivElement; private update!: Update; - private cacheIsVisible = false; highlightedCells = new HighlightedCells(); canvas!: HTMLCanvasElement; @@ -43,7 +44,6 @@ export class PixiApp { headings!: GridHeadings; boxCells!: BoxCells; cellsSheets!: CellsSheets; - quadrants!: Quadrants; pointer!: Pointer; viewportContents!: Container; htmlPlaceholders!: HtmlPlaceholders; @@ -56,7 +56,10 @@ export class PixiApp { // for testing purposes debug!: Graphics; + initialized = false; + async init() { + this.initialized = true; await loadAssets(); this.initCanvas(); await this.rebuild(); @@ -109,16 +112,12 @@ export class PixiApp { // hack to ensure pointermove works outside of canvas this.viewport.off('pointerout'); - // this holds the viewport's contents so it can be reused in Quadrants + // this holds the viewport's contents this.viewportContents = this.viewport.addChild(new Container()); // useful for debugging at viewport locations this.debug = this.viewportContents.addChild(new Graphics()); - // todo... - this.quadrants = new Quadrants(); //this.viewportContents.addChild(new Quadrants(this)); - this.quadrants.visible = false; - this.gridLines = this.viewportContents.addChild(new GridLines()); this.axesLines = this.viewportContents.addChild(new AxesLines()); this.cellsSheets = this.viewportContents.addChild(new CellsSheets()); @@ -150,31 +149,6 @@ export class PixiApp { document.removeEventListener('cut', cutToClipboardEvent); } - private showCache(): void { - if (debugShowCacheFlag && !this.quadrants.visible) { - const cacheOn = document.querySelector('.debug-show-cache-on'); - if (cacheOn) { - (cacheOn as HTMLSpanElement).innerHTML = 'CACHE'; - } - } - // this.cells.changeVisibility(false); - this.quadrants.visible = true; - this.cacheIsVisible = true; - } - - private showCells(): void { - // if (debugShowCacheFlag && !this.cells.visible) { - // const cacheOn = document.querySelector('.debug-show-cache-on') as HTMLSpanElement; - // if (cacheOn) { - // cacheOn.innerHTML = ''; - // } - // } - // this.cells.dirty = true; - // this.cells.changeVisibility(true); - this.quadrants.visible = false; - this.cacheIsVisible = false; - } - setViewportDirty(): void { this.viewport.dirty = true; } @@ -187,12 +161,7 @@ export class PixiApp { this.cursor.dirty = true; this.cellsSheets?.cull(this.viewport.getVisibleBounds()); sheets.sheet.cursor.viewport = this.viewport.lastViewport!; - - // if (!debugNeverShowCache && (this.viewport.scale.x < QUADRANT_SCALE || debugAlwaysShowCache)) { - // this.showCache(); - // } else { - // this.showCells(); - // } + multiplayer.sendViewport(this.saveMultiplayerViewport()); }; attach(parent: HTMLDivElement): void { @@ -208,7 +177,6 @@ export class PixiApp { this.update.destroy(); this.renderer.destroy(true); this.viewport.destroy(); - this.quadrants.destroy(); this.removeListeners(); this.destroyed = true; } @@ -227,14 +195,13 @@ export class PixiApp { this.cursor.dirty = true; }; - // called before and after a quadrant render + // called before and after a render prepareForCopying(options?: { gridLines?: boolean; cull?: Rectangle }): Container { this.gridLines.visible = options?.gridLines ?? false; this.axesLines.visible = false; this.cursor.visible = false; this.multiplayerCursor.visible = false; this.headings.visible = false; - this.quadrants.visible = false; this.boxCells.visible = false; this.htmlPlaceholders.prepare(); this.cellsSheets.toggleOutlines(false); @@ -251,7 +218,6 @@ export class PixiApp { this.multiplayerCursor.visible = true; this.headings.visible = true; this.boxCells.visible = true; - this.quadrants.visible = this.cacheIsVisible; this.htmlPlaceholders.hide(); this.cellsSheets.toggleOutlines(); if (culled) { @@ -278,22 +244,6 @@ export class PixiApp { pixiAppSettings.setEditorInteractionState?.(editorInteractionStateDefault); } - // Pre-renders quadrants by cycling through one quadrant per frame - preRenderQuadrants(resolve?: () => void): Promise { - return new Promise((_resolve) => { - if (!resolve) { - resolve = _resolve; - } - this.quadrants.update(0); - if (this.quadrants.needsUpdating()) { - // the timeout allows the quadratic logo animation to appear smooth - setTimeout(() => this.preRenderQuadrants(resolve), 100); - } else { - resolve(); - } - }); - } - async rebuild() { sheets.create(); await this.cellsSheets.create(); @@ -330,6 +280,36 @@ export class PixiApp { } } + saveMultiplayerViewport(): string { + const viewport = this.viewport; + return JSON.stringify({ + x: viewport.center.x, + y: viewport.center.y, + bounds: viewport.getVisibleBounds(), + }); + } + + loadMultiplayerViewport(options: { x: number; y: number; bounds: Rectangle }): void { + const { x, y, bounds } = options; + let width: number | undefined; + let height: number | undefined; + + // ensure the entire follow-ee's bounds is visible to the current user + if (this.viewport.screenWidth / this.viewport.screenHeight > bounds.width / bounds.height) { + height = bounds.height; + } else { + width = bounds.width; + } + this.viewport.animate({ + position: new Point(x, y), + width, + height, + removeOnInterrupt: true, + time: MULTIPLAYER_VIEWPORT_EASE_TIME, + }); + this.viewport.dirty = true; + } + updateCursorPosition( options = { ensureVisible: true, diff --git a/quadratic-client/src/gridGL/pixiApp/PixiAppSettings.ts b/quadratic-client/src/gridGL/pixiApp/PixiAppSettings.ts index c5ec0b981a..6e895a6d4f 100644 --- a/quadratic-client/src/gridGL/pixiApp/PixiAppSettings.ts +++ b/quadratic-client/src/gridGL/pixiApp/PixiAppSettings.ts @@ -1,3 +1,4 @@ +import { multiplayer } from '@/multiplayer/multiplayer'; import { ApiTypes } from 'quadratic-shared/typesAndSchemas'; import { EditorInteractionState, editorInteractionStateDefault } from '../../atoms/editorInteractionStateAtom'; import { sheets } from '../../grid/controller/Sheets'; @@ -13,6 +14,8 @@ export enum PanMode { interface Input { show: boolean; initialValue?: string; + value?: string; + cursor?: number; x?: number; y?: number; sheetId?: string; @@ -56,7 +59,6 @@ class PixiAppSettings { pixiApp.axesLines.dirty = true; pixiApp.headings.dirty = true; - // only rebuild quadrants if showCellTypeOutlines change if ( (this.lastSettings && this.lastSettings.showCellTypeOutlines !== this.settings.showCellTypeOutlines) || (this.lastSettings && this.lastSettings.presentationMode !== this.settings.presentationMode) @@ -119,6 +121,9 @@ class PixiAppSettings { } changeInput(input: boolean, initialValue?: string) { + if (input === false) { + multiplayer.sendEndCellEdit(); + } if ( this._input.show === true && this._input.x !== undefined && @@ -130,8 +135,12 @@ class PixiAppSettings { if (input === true) { const x = sheets.sheet.cursor.cursorPosition.x; const y = sheets.sheet.cursor.cursorPosition.y; - this._input = { show: input, initialValue, x, y, sheetId: sheets.sheet.id }; - pixiApp.cellsSheets.showLabel(x, y, sheets.sheet.id, false); + if (multiplayer.cellIsBeingEdited(x, y, sheets.sheet.id)) { + this._input = { show: false }; + } else { + this._input = { show: input, initialValue, x, y, sheetId: sheets.sheet.id }; + pixiApp.cellsSheets.showLabel(x, y, sheets.sheet.id, false); + } } else { this._input = { show: false }; } diff --git a/quadratic-client/src/gridGL/quadrants/Quadrant.ts b/quadratic-client/src/gridGL/quadrants/Quadrant.ts deleted file mode 100644 index 5e550058ab..0000000000 --- a/quadratic-client/src/gridGL/quadrants/Quadrant.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { Container, Graphics, MIPMAP_MODES, Rectangle, RenderTexture, Sprite } from 'pixi.js'; -import { debugShowCacheInfo, debugShowTime } from '../../debugFlags'; -import { Sheet } from '../../grid/sheet/Sheet'; -import { intersects } from '../helpers/intersects'; -import { Coordinate } from '../types/size'; -import { QUADRANT_SCALE } from './quadrantConstants'; - -// subquadrants are sprites that live within a quadrant mapped to a rendered texture size -interface SubQuadrant extends Sprite { - subQuadrantX: number; - subQuadrantY: number; - texture: RenderTexture; -} - -// A quadrant is a cached portion of the sheet mapped to column, row size (which can change based on heading size) -// at the default heading size, one subquadrant is needed per quadrant -export class Quadrant extends Container { - private sheet: Sheet; - private subquadrants: SubQuadrant[]; - private _dirty = true; - private overflowLeft = false; - - visibleRectangle!: Rectangle; - location: Coordinate; - - private testGraphics: Graphics; - - constructor(sheet: Sheet, quadrantX: number, quadrantY: number) { - super(); - this.sheet = sheet; - this.location = { x: quadrantX, y: quadrantY }; - this.subquadrants = []; - this.testGraphics = this.addChild(new Graphics()); - this.reposition(); - } - - reposition(horizontal?: boolean) { - // const oldRectangle = this.visibleRectangle; - // const columnStart = this.location.x * QUADRANT_COLUMNS; - // const rowStart = this.location.y * QUADRANT_ROWS; - // this.visibleRectangle = this.sheet.gridOffsets.getScreenRectangle( - // columnStart, - // rowStart, - // QUADRANT_COLUMNS, - // QUADRANT_ROWS - // ); - // // reposition subQuadrants based on any deltas - // if (oldRectangle) { - // const deltaX = this.visibleRectangle.x - oldRectangle.x; - // const deltaY = this.visibleRectangle.y - oldRectangle.y; - // if (deltaX || deltaY) { - // this.children.forEach((child) => { - // child.x += deltaX; - // child.y += deltaY; - // }); - // } - // } - // // if there is an overflow into this quadrant, then we need to redraw the quadrant when we get the chance - // if (horizontal && this.overflowLeft) { - // this.dirty = true; - // } - } - - set dirty(value: boolean) { - if (this._dirty !== value) { - this._dirty = value; - this.visible = !value; - } - } - get dirty(): boolean { - return this._dirty; - } - - // creates/reuses a Sprite with an appropriately sized RenderTexture - private getSubQuadrant(subQuadrantX: number, subQuadrantY: number, width: number, height: number): SubQuadrant { - let sprite = this.subquadrants.find((child) => { - const spriteQuadrant = child as SubQuadrant; - if (spriteQuadrant.subQuadrantX === subQuadrantX && spriteQuadrant.subQuadrantY === subQuadrantY) { - return true; - } - return false; - }) as SubQuadrant; - if (sprite) { - // reuse existing sprite and resize texture if needed - if (sprite.texture.width !== width || sprite.texture.height !== height) { - sprite.texture.resize(width, height, true); - } - sprite.visible = true; - } else { - // create and position a Sprite with the appropriately sized RenderTexture - const texture = RenderTexture.create({ - width, - height, - resolution: Math.max(2, window.devicePixelRatio), - mipmap: MIPMAP_MODES.ON, - }); - sprite = this.addChild(new Sprite(texture)) as SubQuadrant; - sprite.scale.set(1 / QUADRANT_SCALE); - sprite.subQuadrantX = subQuadrantX; - sprite.subQuadrantY = subQuadrantY; - this.subquadrants.push(sprite); - } - return sprite; - } - - private clear(): void { - this.subquadrants.forEach((subquadrant) => (subquadrant.visible = false)); - } - - update(timeStart?: number, debug?: string): void { - if (!this.dirty) return; - this.clear(); - // const columnStart = this.location.x * QUADRANT_COLUMNS; - // const rowStart = this.location.y * QUADRANT_ROWS; - // const screenRectangle = this.sheet.gridOffsets.getScreenRectangle( - // columnStart, - // rowStart, - // QUADRANT_COLUMNS, - // QUADRANT_ROWS - // ); - - // if (debugShowQuadrantBoxes) { - // this.testGraphics - // .clear() - // .beginFill(Math.floor(Math.random() * 0xffffff), 0.25) - // .drawRect(screenRectangle.x, screenRectangle.y, screenRectangle.width, screenRectangle.height) - // .endFill(); - // } - // // number of subquadrants necessary (should be equal to 1 unless heading size has changed) - // const xCount = Math.ceil(screenRectangle.width / QUADRANT_TEXTURE_SIZE); - // const yCount = Math.ceil(screenRectangle.height / QUADRANT_TEXTURE_SIZE); - - // const subQuadrantWidth = screenRectangle.width / xCount; - // const subQuadrantHeight = screenRectangle.height / yCount; - - // for (let subQuadrantY = 0; subQuadrantY < yCount; subQuadrantY++) { - // for (let subQuadrantX = 0; subQuadrantX < xCount; subQuadrantX++) { - // const cellBounds = new Rectangle( - // screenRectangle.x + subQuadrantX * subQuadrantWidth, - // screenRectangle.y + subQuadrantY * subQuadrantHeight, - // subQuadrantWidth + 1, - // subQuadrantHeight + 1 - // ); - // draw quadrant and return the reduced subQuadrant rectangle (ie, shrinks the texture based on what was actually drawn) - // const reducedDrawingRectangle = app.quadrants.cells.drawCells(this.sheet, cellBounds, true); - // if (reducedDrawingRectangle) { - // // adjust the texture placement so we only render boundary cells for subquadrants once (the second time will be outside the texture) - // const trimLeft = - // reducedDrawingRectangle.left < cellBounds.left ? cellBounds.left - reducedDrawingRectangle.left : 0; - // const trimRight = - // reducedDrawingRectangle.right > cellBounds.right ? reducedDrawingRectangle.right - cellBounds.right : 0; - // const trimTop = - // reducedDrawingRectangle.top < cellBounds.top ? cellBounds.top - reducedDrawingRectangle.top : 0; - // const trimBottom = - // reducedDrawingRectangle.bottom > cellBounds.bottom ? reducedDrawingRectangle.bottom - cellBounds.bottom : 0; - // const textureWidth = (reducedDrawingRectangle.width - trimLeft - trimRight) * QUADRANT_SCALE; - // const textureHeight = (reducedDrawingRectangle.height - trimTop - trimBottom) * QUADRANT_SCALE; - // // skip quadrants that have no size - // if (textureWidth <= 0 || textureHeight <= 0) continue; - // const subQuadrant = this.getSubQuadrant(subQuadrantX, subQuadrantY, textureWidth, textureHeight); - // this.overflowLeft = !!trimLeft; - // // prepare a transform to translate the world to the start of the content for this subQuadrant, and properly scale it - // const transform = new Matrix(); - // transform.translate(-reducedDrawingRectangle.left - trimLeft, -reducedDrawingRectangle.top - trimTop); - // transform.scale(QUADRANT_SCALE, QUADRANT_SCALE); - // if (debugShowSubCacheInfo) { - // console.log( - // `[Quadrant] ${this.debugName()}.[${subQuadrantX},${subQuadrantY}] [${cellBounds.toString()} texture size: (${textureWidth}, ${textureHeight})` - // ); - // } - // // render the sprite's texture - // app.renderer.render(app.quadrants.container, { renderTexture: subQuadrant.texture, transform, clear: true }); - // subQuadrant.position.set(reducedDrawingRectangle.left + trimLeft, reducedDrawingRectangle.top + trimTop); - // if (debugShowQuadrantBoxes) { - // this.testGraphics - // .lineStyle({ color: 0, width: 5 }) - // .drawRect( - // reducedDrawingRectangle.x + trimLeft, - // reducedDrawingRectangle.y + trimTop, - // textureWidth / QUADRANT_SCALE, - // textureHeight / QUADRANT_SCALE - // ); - // } - // } - // } - // } - // this.visibleRectangle = screenRectangle; - - if (debugShowTime && debugShowCacheInfo && timeStart) { - console.log(`[Quadrant] Rendered ${this.debugName()} ${debug} (${Math.round(performance.now() - timeStart)} ms)`); - } - this.dirty = false; - } - - debugName(): string { - return `Sheet[${this.sheet.name}]Q[${this.location.x},${this.location.y}]`; - } - - debugTextureCount(): number { - return this.children.reduce((count, child) => count + (child.visible ? 1 : 0), 0) - 1; - } - - cull(bounds: Rectangle): void { - if (this.dirty) { - this.visible = false; - } else { - this.visible = intersects.rectangleRectangle(bounds, this.visibleRectangle); - } - } -} diff --git a/quadratic-client/src/gridGL/quadrants/Quadrants.ts b/quadratic-client/src/gridGL/quadrants/Quadrants.ts deleted file mode 100644 index dcdd82f7ed..0000000000 --- a/quadratic-client/src/gridGL/quadrants/Quadrants.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { Container } from 'pixi.js'; -import { debugShowCacheFlag, debugSkipQuadrantRendering } from '../../debugFlags'; -import { sheets } from '../../grid/controller/Sheets'; -import { Sheet } from '../../grid/sheet/Sheet'; -import { pixiApp } from '../pixiApp/PixiApp'; -import { Coordinate } from '../types/size'; -import { Quadrant } from './Quadrant'; -import { QuadrantsSheet } from './QuadrantsSheet'; -import { QUADRANT_COLUMNS, QUADRANT_ROWS } from './quadrantConstants'; - -export interface QuadrantChanged { - row?: number; - column?: number; - cells?: Coordinate[]; - range?: { start: Coordinate; end: Coordinate }; -} - -// QuadrantsSheet rendered for each Sheet in a file -export class Quadrants extends Container { - private quadrants: Map; - - // used to render cells in Quadrant - container: Container; - - constructor() { - super(); - this.quadrants = new Map(); - this.container = new Container(); - // this.cells = this.container.addChild(new Cells(app)); - // this.container.addChildAt(this.cells.cellsBackground, 0); - } - - static getKey(x: number, y: number): string { - return `${Math.floor(x / QUADRANT_COLUMNS)},${Math.floor(y / QUADRANT_ROWS)}`; - } - - changeSheet(): void { - const quadrantsSheets = Array.from(this.quadrants.values()); - const activeId = sheets.sheet.id; - const quadrantsSheet = this.quadrants.get(activeId); - if (!quadrantsSheet) { - throw new Error('Expected to find QuadrantsSheet in Quadrants.changeSheet'); - } - quadrantsSheets.forEach((q) => (q.visible = q.sheet.id === activeId)); - if (debugShowCacheFlag) { - const dirtyCount = quadrantsSheet.children.reduce( - (count, child) => count + ((child as Quadrant).dirty ? 1 : 0), - 0 - ); - (document.querySelector('.debug-show-cache-count') as HTMLSpanElement).innerHTML = `Quadrants: ${ - quadrantsSheet.children.length - dirtyCount - }/${quadrantsSheet.children.length}`; - } - } - - // adds a newly created sheet to the quadrants - addSheet(sheet: Sheet): void { - const quadrantsSheet = this.addChild(new QuadrantsSheet(sheet)); - this.quadrants.set(sheet.id, quadrantsSheet); - } - - // deletes the quadrants for a delete sheet - deleteSheet(sheet: Sheet): void { - const child = this.quadrants.get(sheet.id); - if (!child) { - throw new Error("Could not find sheet's quadrants to delete"); - } - this.quadrants.delete(sheet.id); - this.removeChild(child); - } - - // rebuilds all quadrants - build(): void { - this.removeChildren(); - this.quadrants.clear(); - sheets.forEach((sheet) => { - const quadrantsSheet = this.addChild(new QuadrantsSheet(sheet)); - this.quadrants.set(sheet.id, quadrantsSheet); - }); - } - - // sorts QuadrantsSheets based on distance to active sheet - private getSortedQuadrantsSheets(): QuadrantsSheet[] { - throw new Error('needs updating'); - // const quadrantsSheets = Array.from(this.quadrants.values()); - // const sheets = this.app.sheetController.sheets; - // const currentIndex = sheets.indexOf(this.app.sheet); - // if (currentIndex === -1) { - // throw new Error('Expected to find index of current sheet in sheets'); - // } - // quadrantsSheets.sort((q1: QuadrantsSheet, q2: QuadrantsSheet) => { - // const q1Index = sheets.findIndex((search) => search.id === q1.sheet.id); - // if (q1Index === -1) { - // throw new Error('Expected to find index of current sheet in sheets'); - // } - // const q2Index = sheets.findIndex((search) => search.id === q2.sheet.id); - // if (q2Index === -1) { - // throw new Error('Expected to find index of current sheet in sheets'); - // } - - // // use the minimum of actual and wrapped distance - // const q1Distance = Math.min(Math.abs(q1Index - currentIndex), Math.abs(q1Index - currentIndex) % sheets.length); - // const q2Distance = Math.min(Math.abs(q2Index - currentIndex), Math.abs(q2Index - currentIndex) % sheets.length); - // return q1Distance - q2Distance; - // }); - // return quadrantsSheets; - } - - needsUpdating(): boolean { - const quadrantsSheets = Array.from(this.quadrants.values()); - const count = !!quadrantsSheets.find((child) => !(child as QuadrantsSheet).complete); - if (debugShowCacheFlag) { - const span = document.querySelector('.debug-show-cache-count') as HTMLSpanElement; - if (span) { - const currentSheet = quadrantsSheets.find((child) => child.sheet === sheets.sheet); - if (currentSheet) { - const dirtyCount = currentSheet.children.reduce( - (count, child) => count + ((child as Quadrant).dirty ? 1 : 0), - 0 - ); - span.innerHTML = `Quadrants: ${currentSheet.children.length - dirtyCount}/${currentSheet.children.length}`; - } - } - } - - return count; - } - - /** - * updates one dirty quadrant per frame(any more and UI felt less responsive, even if within frame time) - * @param timeStart used for console debugging - * @returns whether the app should rerender if quadrants are visible and the updated quadrant is visible - */ - update(timeStart: number): boolean { - if (debugSkipQuadrantRendering) return false; - - const sortedQuadrantsSheet = this.getSortedQuadrantsSheets(); - for (const quadrantsSheet of sortedQuadrantsSheet) { - const updated = quadrantsSheet.update(timeStart); - if (updated !== 'not dirty') { - // debug only if it is the active sheet - if (quadrantsSheet.sheet === sheets.sheet) { - return updated; - } else { - return false; - } - } - } - return false; - } - - /** marks quadrants dirty based on what has changed */ - quadrantChanged(options: QuadrantChanged, sheet?: Sheet): void { - // sheet = sheet ?? this.app.sheet; - // const quadrantsSheet = this.quadrants.get(sheet.id); - // if (!quadrantsSheet) { - // throw new Error('Expected to find quadrantsSheet in quadrants.quadrantChanged'); - // } - // quadrantsSheet.quadrantChanged(options); - } - - /** Returns CellRectangles for visible dirty quadrants */ - // getCellsForDirtyQuadrants(): CellRectangle[] { - // const { viewport } = pixiApp; - // const { grid, borders, id } = sheets.sheet; - // const quadrantsSheet = this.quadrants.get(id); - // if (!quadrantsSheet) { - // throw new Error('Expected quadrantsSheet to be defined in getCellsForDirtyQuadrants'); - // } - // const screen = viewport.getVisibleBounds(); - // return quadrantsSheet.children.flatMap((child) => { - // const quadrant = child as Quadrant; - // if (!quadrant.dirty && !debugShowCellsForDirtyQuadrants) return []; - // if (intersects.rectangleRectangle(screen, quadrant.visibleRectangle)) { - // const columnStart = quadrant.location.x * QUADRANT_COLUMNS; - // const rowStart = quadrant.location.y * QUADRANT_ROWS; - // const cellRectangle = grid.getCells( - // new Rectangle(columnStart, rowStart, QUADRANT_COLUMNS - 1, QUADRANT_ROWS - 1) - // ); - // cellRectangle.addBorders(borders); - // return [cellRectangle]; - // } - // return []; - // }); - // } - - private debugCacheStats(): void { - const textures = this.children.reduce((count, child) => count + (child as Quadrant).debugTextureCount(), 0); - console.log(`[Quadrants] Rendered ${textures} quadrant textures.`); - } - - cull(): void { - const bounds = pixiApp.viewport.getVisibleBounds(); - this.children.forEach((child) => { - (child as Quadrant).cull(bounds); - }); - } -} diff --git a/quadratic-client/src/gridGL/quadrants/QuadrantsSheet.ts b/quadratic-client/src/gridGL/quadrants/QuadrantsSheet.ts deleted file mode 100644 index 1ea9ba66f2..0000000000 --- a/quadratic-client/src/gridGL/quadrants/QuadrantsSheet.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { Container, Rectangle } from 'pixi.js'; -import { debugShowCacheInfo } from '../../debugFlags'; -import { Sheet } from '../../grid/sheet/Sheet'; -import { intersects } from '../helpers/intersects'; -import { pixiApp } from '../pixiApp/PixiApp'; -import { Coordinate } from '../types/size'; -import { Quadrant } from './Quadrant'; -import { QuadrantChanged } from './Quadrants'; -import { QUADRANT_COLUMNS, QUADRANT_ROWS } from './quadrantConstants'; - -// quadrants for one Sheet -export class QuadrantsSheet extends Container { - private quadrants: Map; - sheet: Sheet; - complete: boolean; - - constructor(sheet: Sheet) { - super(); - this.sheet = sheet; - this.quadrants = new Map(); - this.complete = false; - this.build(); - } - - getQuadrantCoordinate(x: number, y: number): Coordinate { - return { - x: Math.floor(x / QUADRANT_COLUMNS), - y: Math.floor(y / QUADRANT_ROWS), - }; - } - - build(): void { - // this.complete = true; - // this.removeChildren(); - // this.quadrants.clear(); - // const { grid, borders } = this.sheet; - // const gridBounds = grid.getSheetBounds(false); - // const borderBounds = borders.getGridBounds(); - // // const renderDependencyBounds = render_dependency.getGridBounds(); - // // const arrayDependencyBounds = array_dependency.getGridBounds(); - // const bounds = intersects.rectangleUnion(gridBounds, borderBounds); - // if (!bounds) return; - // iterate through visible grid bounds and prepare quadrants - // const yStart = Math.floor(bounds.top / QUADRANT_ROWS); - // const yEnd = Math.floor(bounds.bottom / QUADRANT_ROWS); - // const xStart = Math.floor(bounds.left / QUADRANT_COLUMNS); - // const xEnd = Math.floor(bounds.right / QUADRANT_COLUMNS); - // for (let y = yStart; y <= yEnd; y++) { - // for (let x = xStart; x <= xEnd; x++) { - // if (this.sheet.hasQuadrant(x, y)) { - // const quadrant = this.addChild(new Quadrant(this.sheet, x, y)); - // this.quadrants.set(`${x},${y}`, quadrant); - // this.complete = false; - // } - // } - // } - // if (debugShowCacheInfo) { - // console.log( - // `[Quadrants] Added ${ - // Math.ceil(bounds.width / QUADRANT_COLUMNS) * Math.ceil(bounds.height / QUADRANT_ROWS) - // } quadrants for sheet ${this.sheet.id} to queue.` - // ); - // } - } - - update(timeStart: number): boolean | 'not dirty' { - const viewport = pixiApp.viewport; - const dirtyCount = this.children.reduce((count, child) => count + ((child as Quadrant).dirty ? 1 : 0), 0); - if (!dirtyCount) return 'not dirty'; - const firstDirty = this.children.find((child) => (child as Quadrant).dirty) as Quadrant; - if (firstDirty) { - if (debugShowCacheInfo) { - firstDirty.update(timeStart, `${this.children.length - dirtyCount}/${this.children.length}`); - } else { - firstDirty.update(); - } - if (dirtyCount === 1 && !this.complete) { - this.complete = true; - if (debugShowCacheInfo) { - this.debugCacheStats(); - // this.sheet.gridOffsets.debugCache(); - } - } - return this.visible && intersects.rectangleRectangle(viewport.getVisibleBounds(), firstDirty.visibleRectangle); - } - return 'not dirty'; - } - - getQuadrant(row: number, column: number, create: boolean): Quadrant | undefined { - let quadrant = this.quadrants.get(`${row},${column}`); - if (quadrant) return quadrant; - if (!create) return; - quadrant = this.addChild(new Quadrant(this.sheet, row, column)); - this.quadrants.set(`${row},${column}`, quadrant); - this.complete = false; - return quadrant; - } - - quadrantChanged(options: QuadrantChanged): void { - // const bounds = this.sheet.grid.getSheetBounds(false); - // if (!bounds) return; - // if (options.row !== undefined) { - // for (let x = bounds.left; x <= bounds.right; x += QUADRANT_COLUMNS) { - // const { x: quadrantX, y: quadrantY } = this.getQuadrantCoordinate(x, options.row); - // const quadrant = this.getQuadrant(quadrantX, quadrantY, false); - // if (quadrant) quadrant.dirty = true; - // // const dependents = this.sheet.render_dependency.getDependents({ x, y: options.row }); - // // dependents?.forEach((dependent) => { - // // const quadrant = this.getQuadrant(dependent.x, dependent.y, false); - // // if (quadrant) quadrant.dirty = true; - // // }); - // } - // // reposition quadrants below the row - // for (let y = options.row + 1; y <= bounds.bottom; y += QUADRANT_ROWS) { - // for (let x = bounds.left; x <= bounds.right; x += QUADRANT_COLUMNS) { - // const { x: quadrantX, y: quadrantY } = this.getQuadrantCoordinate(x, y); - // const quadrant = this.getQuadrant(quadrantX, quadrantY, false); - // quadrant?.reposition(); - // } - // } - // } - // if (options.column !== undefined) { - // for (let y = bounds.top; y <= bounds.bottom; y += QUADRANT_ROWS) { - // const { x: quadrantX, y: quadrantY } = this.getQuadrantCoordinate(options.column, y); - // const quadrant = this.getQuadrant(quadrantX, quadrantY, false); - // if (quadrant) quadrant.dirty = true; - // } - // // reposition quadrants to the right of the column - // for (let y = bounds.top; y <= bounds.bottom; y += QUADRANT_ROWS) { - // for (let x = options.column + 1; x <= bounds.right; x += QUADRANT_COLUMNS) { - // const { x: quadrantX, y: quadrantY } = this.getQuadrantCoordinate(x, y); - // const quadrant = this.getQuadrant(quadrantX, quadrantY, false); - // quadrant?.reposition(true); - // } - // } - // } - // // set quadrant of list of cells dirty - // if (options.cells) { - // const quadrants = new Set(); - // options.cells.forEach((coordinate) => { - // const { x: quadrantX, y: quadrantY } = this.getQuadrantCoordinate(coordinate.x, coordinate.y); - // const key = `${quadrantX},${quadrantY}`; - // const quadrant = this.getQuadrant(quadrantX, quadrantY, true); - // if (quadrant) quadrant.dirty = true; - // quadrants.add(key); - // }); - // } - // // set range of cells dirty - // if (options.range) { - // const { start, end } = options.range; - // const quadrants = new Set(); - // for (let y = start.y; y <= end.y; y++) { - // for (let x = start.x; x <= end.x; x++) { - // const { x: quadrantX, y: quadrantY } = this.getQuadrantCoordinate(x, y); - // const key = `${quadrantX},${quadrantY}`; - // if (!quadrants.has(key)) { - // const quadrant = this.getQuadrant(quadrantX, quadrantY, false); - // if (quadrant) quadrant.dirty = true; - // quadrants.add(key); - // } - // } - // } - // } - } - - private debugCacheStats(): void { - const textures = this.children.reduce((count, child) => count + (child as Quadrant).debugTextureCount(), 0); - console.log(`[Quadrants] Rendered ${textures} quadrant textures.`); - } - - cull(bounds: Rectangle): void { - this.quadrants.forEach((quadrant) => quadrant.cull(bounds)); - } -} diff --git a/quadratic-client/src/gridGL/quadrants/quadrantConstants.ts b/quadratic-client/src/gridGL/quadrants/quadrantConstants.ts deleted file mode 100644 index e284474582..0000000000 --- a/quadratic-client/src/gridGL/quadrants/quadrantConstants.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { CELL_HEIGHT, CELL_WIDTH } from '../../constants/gridConstants'; - -export const QUADRANT_SCALE = 0.75; -export const QUADRANT_TEXTURE_SIZE = 2048; - -// maximum number of columns and rows of default size that fits in the texture -export const QUADRANT_COLUMNS = Math.floor(QUADRANT_TEXTURE_SIZE / CELL_WIDTH); -export const QUADRANT_ROWS = Math.floor(QUADRANT_TEXTURE_SIZE / CELL_HEIGHT); - -// number of ms to wait after a user interaction before rendering more quadrants -export const QUADRANT_RENDER_WAIT = 200; diff --git a/quadratic-client/src/multiplayer/multiplayer.ts b/quadratic-client/src/multiplayer/multiplayer.ts index f210aade71..53a44545b7 100644 --- a/quadratic-client/src/multiplayer/multiplayer.ts +++ b/quadratic-client/src/multiplayer/multiplayer.ts @@ -1,179 +1,441 @@ +import { debugShowMultiplayer } from '@/debugFlags'; +import { grid } from '@/grid/controller/Grid'; +import { sheets } from '@/grid/controller/Sheets'; import { pixiApp } from '@/gridGL/pixiApp/PixiApp'; -import { Coordinate } from '@/gridGL/types/size'; +import { pixiAppSettings } from '@/gridGL/pixiApp/PixiAppSettings'; import { User } from '@auth0/auth0-spa-js'; -import { Rectangle } from 'pixi.js'; +import { v4 as uuid } from 'uuid'; + +import { authClient } from '@/auth'; import { MULTIPLAYER_COLORS } from './multiplayerCursor/multiplayerColors'; -import { MessageChangeSelection, MessageMouseMove, ReceiveMessages, SendEnterRoom } from './multiplayerTypes'; +import { + Heartbeat, + MessageTransaction, + MessageUserUpdate, + MultiplayerUser, + ReceiveMessages, + ReceiveRoom, + ReceiveTransactions, + SendEnterRoom, + SendGetTransactions, +} from './multiplayerTypes'; const UPDATE_TIME = 1000 / 30; - -// todo: create types for messages - -export interface Player { - sheetId: string; - x?: number; - y?: number; - name: string; - picture: string; - color: number; - visible: boolean; - selection?: { cursor: Coordinate; rectangle?: Rectangle }; -} +const HEARTBEAT_TIME = 1000 * 15; +const RECONNECT_AFTER_ERROR_TIMEOUT = 1000 * 5; export class Multiplayer { private websocket?: WebSocket; - private ready = false; + private state: 'not connected' | 'connecting' | 'connected' | 'waiting to reconnect'; + private sessionId; private room?: string; - private uuid?: string; + private user?: User; + private jwt?: string | void; + + // messages pending a reconnect + private waitingForConnection: { (value: unknown): void }[] = []; // queue of items waiting to be sent to the server on the next tick - private queue: { move?: MessageMouseMove; selection?: MessageChangeSelection } = {}; + private userUpdate: MessageUserUpdate; private lastTime = 0; + private lastHeartbeat = 0; - // keep track of the next player's color index + // next player's color index private nextColor = 0; - players: Map = new Map(); + // users currently logged in to the room + users: Map = new Map(); + + constructor() { + this.state = 'not connected'; + this.sessionId = uuid(); + this.userUpdate = { type: 'UserUpdate', session_id: this.sessionId, file_id: '', update: {} }; + } + + private async getJwt() { + this.jwt = await authClient.getToken(); + } + + private async addJwtCookie(force: boolean = false) { + if (force || !this.jwt) { + await this.getJwt(); + + if (this.jwt) { + document.cookie = `jwt=${this.jwt}; path=/;`; + } + } + } private async init() { + if (this.state === 'connected') return; + + await this.addJwtCookie(); + return new Promise((resolve) => { + if (this.state === 'connecting' || this.state === 'waiting to reconnect') { + this.waitingForConnection.push(resolve); + return; + } + + this.state = 'connecting'; this.websocket = new WebSocket(import.meta.env.VITE_QUADRATIC_MULTIPLAYER_URL); - this.websocket.addEventListener('message', this.handleMessage); - this.websocket.addEventListener('close', async () => { - console.log('[Multiplayer] websocket closed. Reconnecting...'); - this.ready = false; - await this.init(); - if (this.room) await this.enterFileRoom(this.room, { sub: this.uuid }); - }); + this.websocket.addEventListener('message', this.receiveMessage); + + this.websocket.addEventListener('close', this.reconnect); + this.websocket.addEventListener('error', this.reconnect); + this.websocket.addEventListener('open', () => { - console.log('[Multiplayer] websocket initialized.'); - this.ready = true; + console.log('[Multiplayer] websocket connected.'); + this.state = 'connected'; + this.waitingForConnection.forEach((resolve) => resolve(0)); resolve(0); + this.waitingForConnection = []; + this.lastHeartbeat = Date.now(); + window.addEventListener('change-sheet', this.sendChangeSheet); }); }); } - async enterFileRoom(uuid: string, user?: User) { - if (!user?.sub) throw new Error('Expected User to be defined'); - if (this.room === uuid) return; - this.room = uuid; - this.uuid = user.sub; - if (!this.ready) await this.init(); - if (!this.websocket) { - throw new Error('[Multiplayer] Websocket not initialized.'); - } + private reconnect = () => { + if (this.state === 'waiting to reconnect') return; + console.log(`[Multiplayer] websocket closed. Reconnecting in ${RECONNECT_AFTER_ERROR_TIMEOUT / 1000}s...`); + this.state = 'waiting to reconnect'; + setTimeout(async () => { + this.state = 'not connected'; + await this.init(); + if (this.room) { + // need the room to rejoin, but clear it so enterFileRoom succeeds + const room = this.room; + this.room = undefined; + await this.enterFileRoom(room, this.user); + } + }, RECONNECT_AFTER_ERROR_TIMEOUT); + }; + + // multiplayer for a file + async enterFileRoom(file_id: string, user?: User) { + // hack for same file different server + // file_id = 'dde9887b-303c-491f-8863-0bfd047cce76'; + + if (!user?.sub) throw new Error('User must be defined to enter a multiplayer room.'); + this.userUpdate.file_id = file_id; + await this.init(); + this.user = user; + // ensure the user doesn't join a room twice + if (this.room === file_id) return; + this.room = file_id; const enterRoom: SendEnterRoom = { type: 'EnterRoom', - - // todo: not sure this is the correct user id + session_id: this.sessionId, user_id: user.sub, - - file_id: uuid, + file_id, + sheet_id: sheets.sheet.id, + selection: sheets.getMultiplayerSelection(), first_name: user.given_name ?? '', last_name: user.family_name ?? '', + email: user.email ?? '', image: user.picture ?? '', + cell_edit: { + active: pixiAppSettings.input.show, + text: pixiAppSettings.input.value ?? '', + cursor: pixiAppSettings.input.cursor ?? 0, + code_editor: pixiAppSettings.editorInteractionState.showCodeEditor, + }, + x: 0, + y: 0, + visible: false, + viewport: pixiApp.saveMultiplayerViewport(), }; - this.websocket.send(JSON.stringify(enterRoom)); - console.log(`[Multiplayer] Entered room.`); + this.websocket!.send(JSON.stringify(enterRoom)); + if (debugShowMultiplayer) console.log(`[Multiplayer] Joined room ${file_id}.`); } - sendMouseMove(x?: number, y?: number) { - if (x === undefined || y === undefined) { - this.queue.move = { - type: 'MouseMove', - user_id: this.uuid!, + // called by Update.ts + async update() { + if (this.state !== 'connected') return; + const now = performance.now(); + if (now - this.lastTime < UPDATE_TIME) return; + + if (Object.keys(this.userUpdate.update).length > 0) { + this.websocket!.send(JSON.stringify(this.userUpdate)); + this.userUpdate.update = {}; + this.lastHeartbeat = now; + } + this.lastTime = now; + if (now - this.lastHeartbeat > HEARTBEAT_TIME) { + const heartbeat: Heartbeat = { + type: 'Heartbeat', + session_id: this.sessionId, file_id: this.room!, }; - } else { - this.queue.move = { - type: 'MouseMove', - user_id: this.uuid!, + this.websocket!.send(JSON.stringify(heartbeat)); + if (debugShowMultiplayer) console.log('[Multiplayer] Sending heartbeat...'); + this.lastHeartbeat = now; + } + } + + // used to pre-populate useMultiplayerUsers.tsx + getUsers(): MultiplayerUser[] { + return Array.from(this.users.values()); + } + + // whether a multiplayer user is already editing a cell + cellIsBeingEdited(x: number, y: number, sheetId: string): boolean { + for (const player of this.users.values()) { + if (player.sheet_id === sheetId && player.cell_edit.active && player.parsedSelection) { + if (player.parsedSelection.cursor.x === x && player.parsedSelection.cursor.y === y) { + return true; + } + } + } + return false; + } + + //#region send messages + //------------------------- + + private getUserUpdate(): MessageUserUpdate { + if (!this.userUpdate) { + this.userUpdate = { + type: 'UserUpdate', + session_id: this.sessionId, file_id: this.room!, - x, - y, + update: {}, }; } + return this.userUpdate; + } + + async sendMouseMove(x?: number, y?: number) { + const userUpdate = this.getUserUpdate().update; + if (x === undefined || y === undefined) { + userUpdate.visible = false; + } else { + userUpdate.x = x; + userUpdate.y = y; + userUpdate.visible = true; + } + } + + async sendSelection(selection: string) { + const userUpdate = this.getUserUpdate().update; + userUpdate.selection = selection; + } + + sendChangeSheet = () => { + const userUpdate = this.getUserUpdate().update; + userUpdate.sheet_id = sheets.sheet.id; + }; + + sendCellEdit(text: string, cursor: number, codeEditor: boolean, bold?: boolean, italic?: boolean) { + const userUpdate = this.getUserUpdate().update; + userUpdate.cell_edit = { + text, + cursor, + active: true, + code_editor: codeEditor, + bold, + italic, + }; + } + + sendEndCellEdit() { + const userUpdate = this.getUserUpdate().update; + userUpdate.cell_edit = { + text: '', + cursor: 0, + active: false, + code_editor: false, + }; + } + + sendViewport(viewport: string) { + const userUpdate = this.getUserUpdate().update; + userUpdate.viewport = viewport; } - sendSelection(cursor: Coordinate, rectangle?: Rectangle) { - this.queue.selection = { - type: 'ChangeSelection', - user_id: this.uuid!, + async sendTransaction(operations: string) { + await this.init(); + // TODO(ddimaria): this ID should be stored somewhere + let id = uuid(); + const message: MessageTransaction = { + type: 'Transaction', + id, + session_id: this.sessionId, file_id: this.room!, - selection: JSON.stringify({ cursor, rectangle }), + operations, }; + this.websocket!.send(JSON.stringify(message)); } - update() { - if (!this.ready || !this.room || !this.uuid) return; - if (!this.websocket) { - throw new Error('[Multiplayer] Websocket not initialized.'); - } - const now = performance.now(); - if (now - this.lastTime < UPDATE_TIME) return; - if (this.queue.move) { - this.websocket.send(JSON.stringify(this.queue.move)); - this.queue.move = undefined; - } - if (this.queue.selection) { - this.websocket.send(JSON.stringify(this.queue.selection)); - this.queue.selection = undefined; - } - this.lastTime = now; + sendGetTransactions(min_sequence_num: number) { + const message: SendGetTransactions = { + type: 'GetTransactions', + session_id: this.sessionId, + file_id: this.room!, + min_sequence_num, + }; + this.websocket!.send(JSON.stringify(message)); } - handleMessage = (e: { data: string }) => { - const data = JSON.parse(e.data) as ReceiveMessages; - const { type } = data; - if (type === 'Room') { - this.players.clear(); - const users = data.room.users; - for (const userId in users) { - // todo: this check should not be needed (eventually) - if (userId !== this.uuid) { - const user = users[userId]; - const { first_name, last_name, image } = user; - this.players.set(userId, { - name: `${first_name} ${last_name}`, - picture: image, - sheetId: '', + //#endregion + + //#region receive messages + //------------------------- + + // updates the React hook to populate the Avatar list + private receiveUsersInRoom(room: ReceiveRoom) { + const remaining = new Set(this.users.keys()); + for (const user of room.users) { + if (user.session_id !== this.sessionId) { + let player = this.users.get(user.session_id); + if (player) { + player.first_name = user.first_name; + player.last_name = user.last_name; + player.image = user.image; + player.sheet_id = user.sheet_id; + player.selection = user.selection; + player.parsedSelection = user.selection ? JSON.parse(user.selection) : undefined; + remaining.delete(user.session_id); + if (debugShowMultiplayer) console.log(`[Multiplayer] Updated player ${user.first_name}.`); + } else { + player = { + session_id: user.session_id, + file_id: user.file_id, + user_id: user.user_id, + first_name: user.first_name, + last_name: user.last_name, + email: user.email, + image: user.image, + sheet_id: user.sheet_id, + selection: user.selection, + parsedSelection: user.selection ? JSON.parse(user.selection) : undefined, + cell_edit: user.cell_edit, x: 0, y: 0, color: this.nextColor, visible: false, - }); + index: this.users.size, + viewport: user.viewport, + }; + this.users.set(user.session_id, player); this.nextColor = (this.nextColor + 1) % MULTIPLAYER_COLORS.length; - console.log(`[Multiplayer] Player ${userId} entered room.`); + if (debugShowMultiplayer) console.log(`[Multiplayer] Player ${user.first_name} entered room.`); } } } - if (type === 'MouseMove') { - // todo: this check should not be needed (eventually) - if (data.user_id !== this.uuid) { - const player = this.players.get(data.user_id); - if (!player) { - throw new Error("Expected Player to be defined before receiving a message of type 'MouseMove'"); - } - if (data.x !== null && data.y !== null) { - player.x = data.x; - player.y = data.y; - player.visible = true; - } else { - player.visible = false; - } + remaining.forEach((sessionId) => { + if (debugShowMultiplayer) console.log(`[Multiplayer] Player ${this.users.get(sessionId)?.first_name} left room.`); + this.users.delete(sessionId); + }); + window.dispatchEvent(new CustomEvent('multiplayer-update', { detail: this.getUsers() })); + pixiApp.multiplayerCursor.dirty = true; + } + + private receiveUserUpdate(data: MessageUserUpdate) { + // this eventually will not be necessarily + if (data.session_id === this.sessionId) return; + const player = this.users.get(data.session_id); + if (!player) { + throw new Error("Expected Player to be defined before receiving a message of type 'MouseMove'"); + } + if (data.file_id !== this.room) { + throw new Error("Expected file_id to match room before receiving a message of type 'MouseMove'"); + } + const update = data.update; + + if (update.x !== null && update.y !== null) { + player.x = update.x; + player.y = update.y; + if (player.sheet_id === sheets.sheet.id) { window.dispatchEvent(new CustomEvent('multiplayer-cursor')); } - } else if (type === 'ChangeSelection') { - // todo: this check should not be needed (eventually) - if (data.user_id !== this.uuid) { - const player = this.players.get(data.user_id); - if (!player) { - throw new Error("Expected Player to be defined before receiving a message of type 'ChangeSelection'"); + } + + if (update.visible !== undefined) { + player.visible = update.visible; + } + + if (update.sheet_id) { + if (player.sheet_id !== update.sheet_id) { + player.sheet_id = update.sheet_id; + if (player.sheet_id === sheets.sheet.id) { + pixiApp.multiplayerCursor.dirty = true; + window.dispatchEvent(new CustomEvent('multiplayer-cursor')); } - player.selection = JSON.parse(data.selection); + } + } + + if (update.selection) { + player.selection = update.selection; + player.parsedSelection = player.selection ? JSON.parse(player.selection) : undefined; + if (player.sheet_id === sheets.sheet.id) { pixiApp.multiplayerCursor.dirty = true; } } + + if (update.cell_edit) { + player.cell_edit = update.cell_edit; + if (player.parsedSelection) { + // hide the label if the player is editing the cell + pixiApp.cellsSheets.showLabel( + player.parsedSelection.cursor.x, + player.parsedSelection.cursor.y, + player.sheet_id, + !player.cell_edit.active + ); + } + window.dispatchEvent( + new CustomEvent('multiplayer-cell-edit', { + detail: { + ...update.cell_edit, + playerColor: MULTIPLAYER_COLORS[player.color], + sessionId: data.session_id, + sheetId: player.sheet_id, + cell: player.parsedSelection?.cursor, + }, + }) + ); + pixiApp.multiplayerCursor.dirty = true; + } + + if (update.viewport) { + player.viewport = update.viewport; + if (pixiAppSettings.editorInteractionState.follow === player.session_id) { + pixiApp.loadMultiplayerViewport(JSON.parse(player.viewport)); + } + } + } + + private receiveTransaction(data: MessageTransaction) { + // todo: this check should not be needed (eventually) + if (data.session_id !== this.sessionId) { + if (data.file_id !== this.room) { + throw new Error("Expected file_id to match room before receiving a message of type 'Transaction'"); + } + grid.multiplayerTransaction(data.operations); + } + } + + private receiveTransactions(data: ReceiveTransactions) { + console.log(data.transactions); + } + + receiveMessage = (e: { data: string }) => { + const data = JSON.parse(e.data) as ReceiveMessages; + console.log(`[Multiplayer] Received receiveMessage ${data.type}`); + const { type } = data; + if (type === 'UsersInRoom') { + this.receiveUsersInRoom(data); + } else if (type === 'UserUpdate') { + this.receiveUserUpdate(data); + } else if (type === 'Transaction') { + this.receiveTransaction(data); + } else if (type === 'Transactions') { + this.receiveTransactions(data); + } else if (type !== 'Empty') { + console.warn(`Unknown message type: ${type}`); + } }; } diff --git a/quadratic-client/src/multiplayer/multiplayerCursor/MulitplayerCursors.tsx b/quadratic-client/src/multiplayer/multiplayerCursor/MulitplayerCursors.tsx index e104c1c86a..0bce06a26d 100644 --- a/quadratic-client/src/multiplayer/multiplayerCursor/MulitplayerCursors.tsx +++ b/quadratic-client/src/multiplayer/multiplayerCursor/MulitplayerCursors.tsx @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ import { sheets } from '@/grid/controller/Sheets'; import { pixiApp } from '@/gridGL/pixiApp/PixiApp'; import { useEffect, useState } from 'react'; @@ -11,29 +10,40 @@ const OFFSCREEN_SIZE = 5; export const MultiplayerCursors = () => { // triggers a render + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, setPlayersTrigger] = useState(0); useEffect(() => { const updatePlayersTrigger = () => setPlayersTrigger((x) => x + 1); window.addEventListener('multiplayer-cursor', updatePlayersTrigger); - return () => window.removeEventListener('multiplayer-cursor', updatePlayersTrigger); - }, []); - - const [currentSheetId, setCurrentSheetId] = useState(sheets.sheet.id); - useEffect(() => { - const changeSheet = () => setCurrentSheetId(sheets.sheet.id); - window.addEventListener('change-sheet', changeSheet); - return () => window.removeEventListener('change-sheet', changeSheet); + window.addEventListener('change-sheet', updatePlayersTrigger); + pixiApp.viewport.on('moved', updatePlayersTrigger); + pixiApp.viewport.on('zoomed', updatePlayersTrigger); + return () => { + window.removeEventListener('multiplayer-cursor', updatePlayersTrigger); + window.removeEventListener('change-sheet', updatePlayersTrigger); + pixiApp.viewport.off('moved', updatePlayersTrigger); + pixiApp.viewport.off('zoomed', updatePlayersTrigger); + }; }, []); return (
- {[...multiplayer.players].flatMap(([id, player]) => { + {[...multiplayer.users].flatMap(([id, player]) => { const color = MULTIPLAYER_COLORS[player.color]; const bounds = pixiApp.viewport.getVisibleBounds(); const rect = pixiApp.canvas.getBoundingClientRect(); const offsetTop = rect.top; - const { x, y, sheetId, name, visible } = player; - if (visible && x !== undefined && y !== undefined /*&& sheetId === currentSheetId*/) { + const { x, y, sheet_id, first_name, last_name, email, visible, index } = player; + let name: string; + if (first_name || last_name) { + name = `${first_name} ${last_name}`; + } else if (email) { + name = email; + } else { + name = `User ${index}`; + } + + if (visible && x !== undefined && y !== undefined && sheet_id === sheets.sheet.id) { const translated = pixiApp.viewport.toScreen(x, y); let offscreen = false; if (x > bounds.right - OFFSCREEN_SIZE) { diff --git a/quadratic-client/src/multiplayer/multiplayerTypes.ts b/quadratic-client/src/multiplayer/multiplayerTypes.ts index 54686f8653..adf82661f9 100644 --- a/quadratic-client/src/multiplayer/multiplayerTypes.ts +++ b/quadratic-client/src/multiplayer/multiplayerTypes.ts @@ -1,47 +1,98 @@ -export interface MessageMouseMove { - type: 'MouseMove'; - user_id: string; - file_id: string; - x?: number | null; - y?: number | null; -} - -export interface ReceiveEnterRoom { - type: 'Room'; - room: { - users: Record< - string, - { - user_id: string; - first_name: string; - last_name: string; - image: string; - } - >; - }; +import { Coordinate } from '@/gridGL/types/size'; +import { Rectangle } from 'pixi.js'; + +export interface CellEdit { + active: boolean; + text: string; + cursor: number; + code_editor: boolean; + bold?: boolean; + italic?: boolean; } -export interface MessageChangeSelection { - type: 'ChangeSelection'; +export interface MultiplayerUserServer { + session_id: string; + file_id: string; user_id: string; + first_name: string; + last_name: string; + email: string; + image: string; + sheet_id: string; + cell_edit: CellEdit; + visible: boolean; + selection?: string; + x?: number; + y?: number; + viewport: string; +} + +// extended by the client +export interface MultiplayerUser extends MultiplayerUserServer { + color: number; + index: number; + parsedSelection?: { cursor: Coordinate; rectangle: Rectangle }; +} + +export interface ReceiveRoom { + type: 'UsersInRoom'; + users: MultiplayerUser[]; +} + +export interface MessageUserUpdate { + type: 'UserUpdate'; + session_id: string; file_id: string; - selection: string; + update: { + cell_edit?: CellEdit; + selection?: string; + sheet_id?: string; + x?: number; + y?: number; + visible?: boolean; + viewport?: string; + }; } -export interface SendEnterRoom { +export interface SendEnterRoom extends MultiplayerUserServer { type: 'EnterRoom'; - user_id: string; +} + +export interface Transaction { + id: string; file_id: string; - first_name: string; - last_name: string; - image: string; + sequence_num: number; + operations: string[]; } export interface MessageTransaction { type: 'Transaction'; - user_id: string; + id: string; + session_id: string; file_id: string; operations: string; } -export type ReceiveMessages = MessageMouseMove | ReceiveEnterRoom | MessageChangeSelection | MessageTransaction; +export interface SendGetTransactions { + type: 'GetTransactions'; + session_id: string; + file_id: string; + min_sequence_num: number; +} + +export interface ReceiveTransactions { + type: 'Transactions'; + transactions: Transaction[]; +} + +export interface Heartbeat { + type: 'Heartbeat'; + session_id: string; + file_id: string; +} + +export interface ReceiveEmpty { + type: 'Empty'; +} + +export type ReceiveMessages = ReceiveRoom | MessageUserUpdate | MessageTransaction | ReceiveEmpty | ReceiveTransactions; diff --git a/quadratic-client/src/schemas/validateAndUpgradeLegacyGridFile.ts b/quadratic-client/src/schemas/validateAndUpgradeLegacyGridFile.ts index 1e46d5f88d..5dada49a73 100644 --- a/quadratic-client/src/schemas/validateAndUpgradeLegacyGridFile.ts +++ b/quadratic-client/src/schemas/validateAndUpgradeLegacyGridFile.ts @@ -3,6 +3,7 @@ import { GridFileSchemaV1_0 } from './GridFileV1_0'; import { GridFileSchemaV1_1, upgradeV1_0toV1_1 } from './GridFileV1_1'; import { GridFileSchemaV1_2, upgradeV1_1toV1_2 } from './GridFileV1_2'; import { GridFileSchemaV1_3, upgradeV1_2toV1_3 } from './GridFileV1_3'; +import { versionGTE as versionGreaterOrEqualTo } from './versioning'; // Ordered by newest first const FILES = [ @@ -12,8 +13,8 @@ const FILES = [ { schema: GridFileSchemaV1_0, updateFn: upgradeV1_0toV1_1 }, ]; -// all versions validated by Rust -const rustFileVersions = ['1.3', '1.4']; +// first file version that used Rust to validate +const firstRustFileVersion = '1.4'; /** * Given arbitrary JSON, validate whether it's a valid file format and return @@ -44,7 +45,7 @@ export function validateAndUpgradeLegacyGridFile(input: any, logOutput: boolean } // rust files are validated by rust - if (rustFileVersions.includes(json.version)) { + if (versionGreaterOrEqualTo(json.version, firstRustFileVersion)) { return json; } diff --git a/quadratic-client/src/schemas/versioning.ts b/quadratic-client/src/schemas/versioning.ts new file mode 100644 index 0000000000..cad4a9f68d --- /dev/null +++ b/quadratic-client/src/schemas/versioning.ts @@ -0,0 +1,22 @@ +export const versionGTE = (file: string, target: string) => { + let fileSplit = file.split('.'); + const fileMajor = parseInt(fileSplit[0]); + const fileMinor = parseInt(fileSplit[1]); + const filePatch = parseInt(fileSplit[2]); + + const targetSplit = target.split('.'); + const targetMajor = parseInt(targetSplit[0]); + const targetMinor = parseInt(targetSplit[1]); + const targetPatch = parseInt(targetSplit[2]); + + if (fileMajor > targetMajor) return true; + if (fileMajor < targetMajor) return false; + + if (fileMinor > targetMinor) return true; + if (fileMinor < targetMinor) return false; + + if (filePatch > targetPatch) return true; + if (filePatch < targetPatch) return false; + + return true; +}; diff --git a/quadratic-client/src/ui/QuadraticApp.tsx b/quadratic-client/src/ui/QuadraticApp.tsx index 50e0f04657..804ee2441c 100644 --- a/quadratic-client/src/ui/QuadraticApp.tsx +++ b/quadratic-client/src/ui/QuadraticApp.tsx @@ -1,3 +1,5 @@ +import { multiplayer } from '@/multiplayer/multiplayer'; +import { useRootRouteLoaderData } from '@/router'; import { useEffect, useRef, useState } from 'react'; import { isMobile } from 'react-device-detect'; import { useRecoilValue, useSetRecoilState } from 'recoil'; @@ -10,8 +12,11 @@ import QuadraticUIContext from './QuadraticUIContext'; import { QuadraticLoading } from './loading/QuadraticLoading'; export default function QuadraticApp() { + const { user } = useRootRouteLoaderData(); + + const [loading, setLoading] = useState(true); - const { permission } = useRecoilValue(editorInteractionStateAtom); + const { permission, uuid } = useRecoilValue(editorInteractionStateAtom); const setLoadedState = useSetRecoilState(pythonStateAtom); const didMount = useRef(false); @@ -67,10 +72,17 @@ export default function QuadraticApp() { setLoadedState((prevState) => ({ ...prevState, pythonState: 'loading' })); initializeWebWorkers(); } - - pixiApp.init().then(() => setLoading(false)); }, [permission, setLoadedState]); + useEffect(() => { + if (uuid && user && !pixiApp.initialized) { + pixiApp.init().then(() => { + multiplayer.enterFileRoom(uuid, user); + setLoading(false) + }); + } + }, [uuid, user]); + if (loading) { return ; } diff --git a/quadratic-client/src/ui/menus/CodeEditor/CodeEditor.tsx b/quadratic-client/src/ui/menus/CodeEditor/CodeEditor.tsx index be0bd0be35..ccf25c889c 100644 --- a/quadratic-client/src/ui/menus/CodeEditor/CodeEditor.tsx +++ b/quadratic-client/src/ui/menus/CodeEditor/CodeEditor.tsx @@ -92,6 +92,7 @@ export const CodeEditor = () => { useEffect(() => { mixpanel.track('[CodeEditor].opened', { type: editorMode }); + multiplayer.sendCellEdit('', 0, true); }, [editorMode]); const closeEditor = useCallback( @@ -105,6 +106,7 @@ export const CodeEditor = () => { })); pixiApp.highlightedCells.clear(); focusGrid(); + multiplayer.sendEndCellEdit(); } }, [codeString, editorContent, setEditorInteractionState] @@ -197,7 +199,6 @@ export const CodeEditor = () => { multiplayer.sendMouseMove(); }} onPointerMove={(e) => { - console.log('hi'); e.stopPropagation(); }} > diff --git a/quadratic-client/src/ui/menus/TopBar/CodeOutlinesSwitch.tsx b/quadratic-client/src/ui/menus/TopBar/CodeOutlinesSwitch.tsx index e6f6d7b7cf..61d374652b 100644 --- a/quadratic-client/src/ui/menus/TopBar/CodeOutlinesSwitch.tsx +++ b/quadratic-client/src/ui/menus/TopBar/CodeOutlinesSwitch.tsx @@ -6,7 +6,7 @@ const CodeOutlinesSwitch = styled(Switch)(({ theme }) => { return { padding: '8px', '& .MuiSwitch-track': { - borderRadius: 22 / 2, + borderRadius: 0, background: '#fff', border: `1px solid ${colors.darkGray}4d`, // hexadecimal opacity: 30% opacity: 1, @@ -52,6 +52,7 @@ const CodeOutlinesSwitch = styled(Switch)(({ theme }) => { width: 12, height: 12, margin: 4, + borderRadius: 0, }, '&:hover .MuiSwitch-thumb': { opacity: 1, diff --git a/quadratic-client/src/ui/menus/TopBar/TopBarUsers.tsx b/quadratic-client/src/ui/menus/TopBar/TopBarUsers.tsx index 7a2109f7c7..42633f20dd 100644 --- a/quadratic-client/src/ui/menus/TopBar/TopBarUsers.tsx +++ b/quadratic-client/src/ui/menus/TopBar/TopBarUsers.tsx @@ -1,36 +1,210 @@ -import { Avatar, AvatarGroup, useTheme } from '@mui/material'; +import { editorInteractionStateAtom } from '@/atoms/editorInteractionStateAtom'; +import { pixiApp } from '@/gridGL/pixiApp/PixiApp'; +import { MULTIPLAYER_COLORS } from '@/multiplayer/multiplayerCursor/multiplayerColors'; +import { TooltipHint } from '@/ui/components/TooltipHint'; +import VisibilityIcon from '@mui/icons-material/Visibility'; +import { Avatar, AvatarGroup, IconButton, useTheme } from '@mui/material'; +import { Menu, MenuItem } from '@szhsin/react-menu'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; import { useRootRouteLoaderData } from '../../../router'; import { colors } from '../../../theme/colors'; -import { TooltipHint } from '../../components/TooltipHint'; +import { useMultiplayerUsers } from './useMultiplayerUsers'; + +const convertName = ( + firstName: string | undefined, + lastName: string | undefined, + email: string | undefined, + you: boolean +): string => { + let name = ''; + if (firstName) { + name += firstName; + } + if (lastName) { + if (firstName) name += ' '; + name += lastName; + } + if (!firstName && !lastName && email) { + name = email; + } + if (you) { + if (name.length) { + name += ' (You)'; + } else { + name += '(You)'; + } + } + return name; +}; + +const convertInitial = (firstName?: string, lastName?: string, email?: string): string => { + if (!firstName && !lastName && email) { + return email[0]; + } + return (firstName ? firstName[0] : '') + (lastName ? lastName[0] : ''); +}; + +// const getDeviceName = (): string => { +// let parser = new UAParser(window.navigator.userAgent); +// let result = parser.getResult(); +// return result.device?.model || result.device?.type || ''; +// } export const TopBarUsers = () => { + const editorInteractionState = useRecoilValue(editorInteractionStateAtom); + const follow = editorInteractionState.follow; + const theme = useTheme(); const { user } = useRootRouteLoaderData(); - const displayName = user?.name ? user.name + ' (You)' : '(You)'; - const initial = user?.name ? user.name[0] : 'Y'; + const displayName = convertName(user?.given_name, user?.family_name, user?.email, true); + const initial = convertInitial(user?.given_name, user?.family_name); + // const device = getDeviceName(); + // console.log(device) + // console.log(window.navigator.userAgent) + const multiplayerUsers = useMultiplayerUsers(); + + const users = multiplayerUsers.filter((user) => user.session_id !== follow); + const userFollow = (follow && multiplayerUsers.find((user) => user.session_id === follow)) || null; + + // todo: black should be quadratic black return ( - - {user && } - + <> + + {users.map((user) => { + return ( + + ); + })} + + + {userFollow && ( + + )} + {user && } + + ); }; -function UserAvatar({ displayName, initial, picture }: { displayName: string; initial: string; picture: string }) { +function You({ + displayName, + initial, + picture, + border, +}: { + displayName: string; + initial: string; + picture: string; + border: string; +}) { + return ( + // IconButton was necessary for the tooltip to work + + + + {initial} + + + + ); +} + +function UserAvatar({ + displayName, + initial, + picture, + border, + sessionId, + follow, + viewport, +}: { + displayName: string; + initial: string; + picture: string; + border: string; + sessionId: string; + follow: boolean; + viewport: string; +}) { + const setEditorInteractionState = useSetRecoilState(editorInteractionStateAtom); + const handleFollow = () => { + setEditorInteractionState((prev) => { + if (follow) { + return { ...prev, follow: undefined }; + } + pixiApp.loadMultiplayerViewport(JSON.parse(viewport)); + return { ...prev, follow: sessionId }; + }); + }; + + const name = follow ? `Following ${displayName}` : displayName; + const avatar = ( + + +
+ + {initial} + + {follow && ( + + )} +
+
+
+ ); + return ( - - - {initial} - - + + {follow ? `Stop following ${displayName}` : `Follow ${displayName}`} + ); } diff --git a/quadratic-client/src/ui/menus/TopBar/useMultiplayerUsers.tsx b/quadratic-client/src/ui/menus/TopBar/useMultiplayerUsers.tsx new file mode 100644 index 0000000000..91c9adf545 --- /dev/null +++ b/quadratic-client/src/ui/menus/TopBar/useMultiplayerUsers.tsx @@ -0,0 +1,16 @@ +import { multiplayer } from '@/multiplayer/multiplayer'; +import { MultiplayerUser } from '@/multiplayer/multiplayerTypes'; +import { useEffect, useState } from 'react'; + +export const useMultiplayerUsers = (): MultiplayerUser[] => { + const [users, setUsers] = useState([]); + + useEffect(() => { + setUsers(multiplayer.getUsers()); + const handleUpdate = (e: any) => setUsers(e.detail); + window.addEventListener('multiplayer-update', handleUpdate); + return () => window.removeEventListener('multiplayer-update', handleUpdate); + }, []); + + return users; +}; diff --git a/quadratic-core/Cargo.toml b/quadratic-core/Cargo.toml index 73457f848f..e32f8632a8 100644 --- a/quadratic-core/Cargo.toml +++ b/quadratic-core/Cargo.toml @@ -41,6 +41,7 @@ serde_repr = "0.1" smallvec = { version = "1.11.0", features = ["serde", "union"] } strum = "0.24.1" strum_macros = "0.24.3" +tabled = { version ="0.14.0", features = ["color"] } pollster = "0.2.5" uuid = { version = "1.4.0", features = ["v4", "serde"] } chrono = { version = "0.4", features = ["serde", "wasmbind"] } @@ -68,7 +69,6 @@ indexmap = "2.0.2" [dev-dependencies] criterion = { version = "0.4", default-features = false } -tabled = { version ="0.14.0", features = ["color"] } tokio-test = "0.4.3" [target.'cfg(not(target_family = "wasm"))'.dev-dependencies] diff --git a/quadratic-core/benches/grid_benchmark.rs b/quadratic-core/benches/grid_benchmark.rs index 82a594b169..2b0f2796d1 100644 --- a/quadratic-core/benches/grid_benchmark.rs +++ b/quadratic-core/benches/grid_benchmark.rs @@ -1,16 +1,17 @@ use criterion::{criterion_group, criterion_main, Bencher, Criterion}; use quadratic_core::controller::GridController; use quadratic_core::grid::Grid; -use quadratic_core::{Pos, Rect}; +use quadratic_core::{Pos, Rect, SheetPos, SheetRect}; use std::time::Duration; criterion_group!(benches, criterion_benchmark); criterion_main!(benches); fn criterion_benchmark(c: &mut Criterion) { - let airports = - quadratic_core::grid::file::import(include_str!("../examples/v1_4_airports_distance.grid")) - .unwrap(); + let airports = quadratic_core::grid::file::import(include_str!( + "../../rust-shared/data/grid/v1_4_airports_distance.grid" + )) + .unwrap(); let inputs = vec![ ("empty", Grid::new()), // empty file @@ -46,13 +47,18 @@ fn criterion_benchmark(c: &mut Criterion) { let mut gc = GridController::from_grid(grid.clone()); b.iter(|| { let sheet_id = gc.sheet_ids()[0]; - let rect = Rect { + let sheet_rect = SheetRect { min: Pos { x: 0, y: 0 }, max: Pos { x: 10, y: 10 }, + sheet_id, }; - let pos = Pos { x: 10000, y: 10000 }; - let contents = gc.copy_to_clipboard(sheet_id, rect); - gc.paste_from_clipboard(sheet_id, pos, Some(contents.0), Some(contents.1), None); + let sheet_pos = SheetPos { + x: 10000, + y: 10000, + sheet_id, + }; + let contents = gc.copy_to_clipboard(sheet_rect); + gc.paste_from_clipboard(sheet_pos, Some(contents.0), Some(contents.1), None); }); }); @@ -60,13 +66,18 @@ fn criterion_benchmark(c: &mut Criterion) { let mut gc = GridController::from_grid(grid.clone()); b.iter(|| { let sheet_id = gc.sheet_ids()[0]; - let rect = Rect { + let sheet_rect = SheetRect { min: Pos { x: 0, y: 0 }, max: Pos { x: 100, y: 100 }, + sheet_id, + }; + let sheet_pos = SheetPos { + x: 10000, + y: 10000, + sheet_id, }; - let pos = Pos { x: 10000, y: 10000 }; - let contents = gc.copy_to_clipboard(sheet_id, rect); - gc.paste_from_clipboard(sheet_id, pos, Some(contents.0), Some(contents.1), None); + let contents = gc.copy_to_clipboard(sheet_rect); + gc.paste_from_clipboard(sheet_pos, Some(contents.0), Some(contents.1), None); }); }); @@ -91,18 +102,19 @@ fn criterion_benchmark(c: &mut Criterion) { // Setup let gc = GridController::from_grid(grid.clone()); let sheet_id = gc.sheet_ids()[0]; - let rect = Rect { + let sheet_rect = SheetRect { min: Pos { x: -10000, y: -10000, }, max: Pos { x: 10000, y: 10000 }, + sheet_id, }; - (gc, sheet_id, rect) + (gc, sheet_rect) }, - |(mut gc, sheet_id, rect)| { + |(mut gc, sheet_rect)| { // Test - gc.delete_cells_rect(sheet_id, rect, None); + gc.delete_cells_rect(sheet_rect, None); }, criterion::BatchSize::SmallInput, ) @@ -114,14 +126,15 @@ fn criterion_benchmark(c: &mut Criterion) { // Setup let mut gc = GridController::from_grid(grid.clone()); let sheet_id = gc.sheet_ids()[0]; - let rect = Rect { + let sheet_rect = SheetRect { min: Pos { x: -10000, y: -10000, }, max: Pos { x: 10000, y: 10000 }, + sheet_id, }; - gc.delete_cells_rect(sheet_id, rect, None); + gc.delete_cells_rect(sheet_rect, None); gc }, |mut gc| { @@ -138,14 +151,15 @@ fn criterion_benchmark(c: &mut Criterion) { // Setup let mut gc = GridController::from_grid(grid.clone()); let sheet_id = gc.sheet_ids()[0]; - let rect = Rect { + let sheet_rect = SheetRect { min: Pos { x: -10000, y: -10000, }, max: Pos { x: 10000, y: 10000 }, + sheet_id, }; - gc.delete_cells_rect(sheet_id, rect, None); + gc.delete_cells_rect(sheet_rect, None); gc.undo(None); gc }, @@ -208,18 +222,19 @@ fn criterion_benchmark(c: &mut Criterion) { // Setup let gc = GridController::from_grid(grid.clone()); let sheet_id = gc.sheet_ids()[0]; - let rect = Rect { + let sheet_rect = SheetRect { min: Pos { x: -10000, y: -10000, }, max: Pos { x: 10000, y: 10000 }, + sheet_id, }; - (gc, sheet_id, rect) + (gc, sheet_rect) }, - |(mut gc, sheet_id, rect)| { + |(mut gc, sheet_rect)| { // Test - gc.clear_formatting(sheet_id, rect, None); + gc.clear_formatting(sheet_rect, None); }, criterion::BatchSize::SmallInput, ) diff --git a/quadratic-core/examples/airports.grid b/quadratic-core/examples/airports.grid deleted file mode 100644 index 404dc1a350..0000000000 --- a/quadratic-core/examples/airports.grid +++ /dev/null @@ -1,54643 +0,0 @@ -{ - "sheets": [ - { - "name": "Sheet1", - "order": "a0", - "borders": [], - "cells": [ - { - "x": 0, - "y": 0, - "type": "TEXT", - "value": "Airport source data", - "last_modified": "2023-02-16T23:48:13.069Z" - }, - { - "x": 0, - "y": 2, - "type": "TEXT", - "value": "index" - }, - { - "x": 0, - "y": 3, - "type": "TEXT", - "value": "0", - "last_modified": "2023-02-17T00:02:03.921Z" - }, - { - "x": 0, - "y": 4, - "type": "TEXT", - "value": "1", - "last_modified": "2023-02-17T00:02:03.958Z" - }, - { - "x": 0, - "y": 5, - "type": "TEXT", - "value": "2", - "last_modified": "2023-02-17T00:02:03.985Z" - }, - { - "x": 0, - "y": 6, - "type": "TEXT", - "value": "3", - "last_modified": "2023-02-17T00:02:04.009Z" - }, - { - "x": 0, - "y": 7, - "type": "TEXT", - "value": "4", - "last_modified": "2023-02-17T00:02:04.032Z" - }, - { - "x": 0, - "y": 8, - "type": "TEXT", - "value": "5", - "last_modified": "2023-02-17T00:02:04.055Z" - }, - { - "x": 0, - "y": 9, - "type": "TEXT", - "value": "6", - "last_modified": "2023-02-17T00:02:04.078Z" - }, - { - "x": 0, - "y": 10, - "type": "TEXT", - "value": "7", - "last_modified": "2023-02-17T00:02:04.100Z" - }, - { - "x": 0, - "y": 11, - "type": "TEXT", - "value": "8", - "last_modified": "2023-02-17T00:02:04.122Z" - }, - { - "x": 0, - "y": 12, - "type": "TEXT", - "value": "9", - "last_modified": "2023-02-17T00:02:04.144Z" - }, - { - "x": 0, - "y": 13, - "type": "TEXT", - "value": "10", - "last_modified": "2023-02-17T00:02:04.166Z" - }, - { - "x": 0, - "y": 14, - "type": "TEXT", - "value": "11", - "last_modified": "2023-02-17T00:02:04.188Z" - }, - { - "x": 0, - "y": 15, - "type": "TEXT", - "value": "12", - "last_modified": "2023-02-17T00:02:04.209Z" - }, - { - "x": 0, - "y": 16, - "type": "TEXT", - "value": "13", - "last_modified": "2023-02-17T00:02:04.230Z" - }, - { - "x": 0, - "y": 17, - "type": "TEXT", - "value": "14", - "last_modified": "2023-02-17T00:02:04.252Z" - }, - { - "x": 0, - "y": 18, - "type": "TEXT", - "value": "15", - "last_modified": "2023-02-17T00:02:04.273Z" - }, - { - "x": 0, - "y": 19, - "type": "TEXT", - "value": "16", - "last_modified": "2023-02-17T00:02:04.294Z" - }, - { - "x": 0, - "y": 20, - "type": "TEXT", - "value": "17", - "last_modified": "2023-02-17T00:02:04.314Z" - }, - { - "x": 0, - "y": 21, - "type": "TEXT", - "value": "18", - "last_modified": "2023-02-17T00:02:04.335Z" - }, - { - "x": 0, - "y": 22, - "type": "TEXT", - "value": "19", - "last_modified": "2023-02-17T00:02:04.356Z" - }, - { - "x": 0, - "y": 23, - "type": "TEXT", - "value": "20", - "last_modified": "2023-02-17T00:02:04.376Z" - }, - { - "x": 0, - "y": 24, - "type": "TEXT", - "value": "21", - "last_modified": "2023-02-17T00:02:04.396Z" - }, - { - "x": 0, - "y": 25, - "type": "TEXT", - "value": "22", - "last_modified": "2023-02-17T00:02:04.416Z" - }, - { - "x": 0, - "y": 26, - "type": "TEXT", - "value": "23", - "last_modified": "2023-02-17T00:02:04.436Z" - }, - { - "x": 0, - "y": 27, - "type": "TEXT", - "value": "24", - "last_modified": "2023-02-17T00:02:04.456Z" - }, - { - "x": 0, - "y": 28, - "type": "TEXT", - "value": "25", - "last_modified": "2023-02-17T00:02:04.476Z" - }, - { - "x": 0, - "y": 29, - "type": "TEXT", - "value": "26", - "last_modified": "2023-02-17T00:02:04.495Z" - }, - { - "x": 0, - "y": 30, - "type": "TEXT", - "value": "27", - "last_modified": "2023-02-17T00:02:04.514Z" - }, - { - "x": 0, - "y": 31, - "type": "TEXT", - "value": "28", - "last_modified": "2023-02-17T00:02:04.534Z" - }, - { - "x": 0, - "y": 32, - "type": "TEXT", - "value": "29", - "last_modified": "2023-02-17T00:02:04.553Z" - }, - { - "x": 0, - "y": 33, - "type": "TEXT", - "value": "30", - "last_modified": "2023-02-17T00:02:04.572Z" - }, - { - "x": 0, - "y": 34, - "type": "TEXT", - "value": "31", - "last_modified": "2023-02-17T00:02:04.591Z" - }, - { - "x": 0, - "y": 35, - "type": "TEXT", - "value": "32", - "last_modified": "2023-02-17T00:02:04.610Z" - }, - { - "x": 0, - "y": 36, - "type": "TEXT", - "value": "33", - "last_modified": "2023-02-17T00:02:04.628Z" - }, - { - "x": 0, - "y": 37, - "type": "TEXT", - "value": "34", - "last_modified": "2023-02-17T00:02:04.647Z" - }, - { - "x": 0, - "y": 38, - "type": "TEXT", - "value": "35", - "last_modified": "2023-02-17T00:02:04.665Z" - }, - { - "x": 0, - "y": 39, - "type": "TEXT", - "value": "36", - "last_modified": "2023-02-17T00:02:04.684Z" - }, - { - "x": 0, - "y": 40, - "type": "TEXT", - "value": "37", - "last_modified": "2023-02-17T00:02:04.702Z" - }, - { - "x": 0, - "y": 41, - "type": "TEXT", - "value": "38", - "last_modified": "2023-02-17T00:02:04.720Z" - }, - { - "x": 0, - "y": 42, - "type": "TEXT", - "value": "39", - "last_modified": "2023-02-17T00:02:04.738Z" - }, - { - "x": 0, - "y": 43, - "type": "TEXT", - "value": "40", - "last_modified": "2023-02-17T00:02:04.755Z" - }, - { - "x": 0, - "y": 44, - "type": "TEXT", - "value": "41", - "last_modified": "2023-02-17T00:02:04.773Z" - }, - { - "x": 0, - "y": 45, - "type": "TEXT", - "value": "42", - "last_modified": "2023-02-17T00:02:04.791Z" - }, - { - "x": 0, - "y": 46, - "type": "TEXT", - "value": "43", - "last_modified": "2023-02-17T00:02:04.808Z" - }, - { - "x": 0, - "y": 47, - "type": "TEXT", - "value": "44", - "last_modified": "2023-02-17T00:02:04.825Z" - }, - { - "x": 0, - "y": 48, - "type": "TEXT", - "value": "45", - "last_modified": "2023-02-17T00:02:04.843Z" - }, - { - "x": 0, - "y": 49, - "type": "TEXT", - "value": "46", - "last_modified": "2023-02-17T00:02:04.860Z" - }, - { - "x": 0, - "y": 50, - "type": "TEXT", - "value": "47", - "last_modified": "2023-02-17T00:02:04.877Z" - }, - { - "x": 0, - "y": 51, - "type": "TEXT", - "value": "48", - "last_modified": "2023-02-17T00:02:04.894Z" - }, - { - "x": 0, - "y": 52, - "type": "TEXT", - "value": "49", - "last_modified": "2023-02-17T00:02:04.911Z" - }, - { - "x": 0, - "y": 53, - "type": "TEXT", - "value": "50", - "last_modified": "2023-02-17T00:02:04.928Z" - }, - { - "x": 0, - "y": 54, - "type": "TEXT", - "value": "51", - "last_modified": "2023-02-17T00:02:04.944Z" - }, - { - "x": 0, - "y": 55, - "type": "TEXT", - "value": "52", - "last_modified": "2023-02-17T00:02:04.961Z" - }, - { - "x": 0, - "y": 56, - "type": "TEXT", - "value": "53", - "last_modified": "2023-02-17T00:02:04.977Z" - }, - { - "x": 0, - "y": 57, - "type": "TEXT", - "value": "54", - "last_modified": "2023-02-17T00:02:04.993Z" - }, - { - "x": 0, - "y": 58, - "type": "TEXT", - "value": "55", - "last_modified": "2023-02-17T00:02:05.009Z" - }, - { - "x": 0, - "y": 59, - "type": "TEXT", - "value": "56", - "last_modified": "2023-02-17T00:02:05.025Z" - }, - { - "x": 0, - "y": 60, - "type": "TEXT", - "value": "57", - "last_modified": "2023-02-17T00:02:05.041Z" - }, - { - "x": 0, - "y": 61, - "type": "TEXT", - "value": "58", - "last_modified": "2023-02-17T00:02:05.057Z" - }, - { - "x": 0, - "y": 62, - "type": "TEXT", - "value": "59", - "last_modified": "2023-02-17T00:02:05.073Z" - }, - { - "x": 0, - "y": 63, - "type": "TEXT", - "value": "60", - "last_modified": "2023-02-17T00:02:05.088Z" - }, - { - "x": 0, - "y": 64, - "type": "TEXT", - "value": "61", - "last_modified": "2023-02-17T00:02:05.104Z" - }, - { - "x": 0, - "y": 65, - "type": "TEXT", - "value": "62", - "last_modified": "2023-02-17T00:02:05.119Z" - }, - { - "x": 0, - "y": 66, - "type": "TEXT", - "value": "63", - "last_modified": "2023-02-17T00:02:05.134Z" - }, - { - "x": 0, - "y": 67, - "type": "TEXT", - "value": "64", - "last_modified": "2023-02-17T00:02:05.150Z" - }, - { - "x": 0, - "y": 68, - "type": "TEXT", - "value": "65", - "last_modified": "2023-02-17T00:02:05.165Z" - }, - { - "x": 0, - "y": 69, - "type": "TEXT", - "value": "66", - "last_modified": "2023-02-17T00:02:05.180Z" - }, - { - "x": 0, - "y": 70, - "type": "TEXT", - "value": "67", - "last_modified": "2023-02-17T00:02:05.195Z" - }, - { - "x": 0, - "y": 71, - "type": "TEXT", - "value": "68", - "last_modified": "2023-02-17T00:02:05.210Z" - }, - { - "x": 0, - "y": 72, - "type": "TEXT", - "value": "69", - "last_modified": "2023-02-17T00:02:05.224Z" - }, - { - "x": 0, - "y": 73, - "type": "TEXT", - "value": "70", - "last_modified": "2023-02-17T00:02:05.239Z" - }, - { - "x": 0, - "y": 74, - "type": "TEXT", - "value": "71", - "last_modified": "2023-02-17T00:02:05.254Z" - }, - { - "x": 0, - "y": 75, - "type": "TEXT", - "value": "72", - "last_modified": "2023-02-17T00:02:05.268Z" - }, - { - "x": 0, - "y": 76, - "type": "TEXT", - "value": "73", - "last_modified": "2023-02-17T00:02:05.282Z" - }, - { - "x": 0, - "y": 77, - "type": "TEXT", - "value": "74", - "last_modified": "2023-02-17T00:02:05.297Z" - }, - { - "x": 0, - "y": 78, - "type": "TEXT", - "value": "75", - "last_modified": "2023-02-17T00:02:05.311Z" - }, - { - "x": 0, - "y": 79, - "type": "TEXT", - "value": "76", - "last_modified": "2023-02-17T00:02:05.325Z" - }, - { - "x": 0, - "y": 80, - "type": "TEXT", - "value": "77", - "last_modified": "2023-02-17T00:02:05.339Z" - }, - { - "x": 0, - "y": 81, - "type": "TEXT", - "value": "78", - "last_modified": "2023-02-17T00:02:05.353Z" - }, - { - "x": 0, - "y": 82, - "type": "TEXT", - "value": "79", - "last_modified": "2023-02-17T00:02:05.367Z" - }, - { - "x": 0, - "y": 83, - "type": "TEXT", - "value": "80", - "last_modified": "2023-02-17T00:02:05.380Z" - }, - { - "x": 0, - "y": 84, - "type": "TEXT", - "value": "81", - "last_modified": "2023-02-17T00:02:05.394Z" - }, - { - "x": 0, - "y": 85, - "type": "TEXT", - "value": "82", - "last_modified": "2023-02-17T00:02:05.408Z" - }, - { - "x": 0, - "y": 86, - "type": "TEXT", - "value": "83", - "last_modified": "2023-02-17T00:02:05.422Z" - }, - { - "x": 0, - "y": 87, - "type": "TEXT", - "value": "84", - "last_modified": "2023-02-17T00:02:05.435Z" - }, - { - "x": 0, - "y": 88, - "type": "TEXT", - "value": "85", - "last_modified": "2023-02-17T00:02:05.448Z" - }, - { - "x": 0, - "y": 89, - "type": "TEXT", - "value": "86", - "last_modified": "2023-02-17T00:02:05.462Z" - }, - { - "x": 0, - "y": 90, - "type": "TEXT", - "value": "87", - "last_modified": "2023-02-17T00:02:05.475Z" - }, - { - "x": 0, - "y": 91, - "type": "TEXT", - "value": "88", - "last_modified": "2023-02-17T00:02:05.488Z" - }, - { - "x": 0, - "y": 92, - "type": "TEXT", - "value": "89", - "last_modified": "2023-02-17T00:02:05.501Z" - }, - { - "x": 0, - "y": 93, - "type": "TEXT", - "value": "90", - "last_modified": "2023-02-17T00:02:05.514Z" - }, - { - "x": 0, - "y": 94, - "type": "TEXT", - "value": "91", - "last_modified": "2023-02-17T00:02:05.527Z" - }, - { - "x": 0, - "y": 95, - "type": "TEXT", - "value": "92", - "last_modified": "2023-02-17T00:02:05.540Z" - }, - { - "x": 0, - "y": 96, - "type": "TEXT", - "value": "93", - "last_modified": "2023-02-17T00:02:05.553Z" - }, - { - "x": 0, - "y": 97, - "type": "TEXT", - "value": "94", - "last_modified": "2023-02-17T00:02:05.565Z" - }, - { - "x": 0, - "y": 98, - "type": "TEXT", - "value": "95", - "last_modified": "2023-02-17T00:02:05.578Z" - }, - { - "x": 0, - "y": 99, - "type": "TEXT", - "value": "96", - "last_modified": "2023-02-17T00:02:05.591Z" - }, - { - "x": 0, - "y": 100, - "type": "TEXT", - "value": "97", - "last_modified": "2023-02-17T00:02:05.603Z" - }, - { - "x": 0, - "y": 101, - "type": "TEXT", - "value": "98", - "last_modified": "2023-02-17T00:02:05.616Z" - }, - { - "x": 0, - "y": 102, - "type": "TEXT", - "value": "99", - "last_modified": "2023-02-17T00:02:05.628Z" - }, - { - "x": 0, - "y": 103, - "type": "TEXT", - "value": "100", - "last_modified": "2023-02-17T00:02:05.640Z" - }, - { - "x": 1, - "y": 2, - "type": "TEXT", - "value": "iata" - }, - { - "x": 1, - "y": 3, - "type": "TEXT", - "value": "00M", - "last_modified": "2023-02-17T00:02:03.928Z" - }, - { - "x": 1, - "y": 4, - "type": "TEXT", - "value": "00R", - "last_modified": "2023-02-17T00:02:03.962Z" - }, - { - "x": 1, - "y": 5, - "type": "TEXT", - "value": "00V", - "last_modified": "2023-02-17T00:02:03.988Z" - }, - { - "x": 1, - "y": 6, - "type": "TEXT", - "value": "01G", - "last_modified": "2023-02-17T00:02:04.012Z" - }, - { - "x": 1, - "y": 7, - "type": "TEXT", - "value": "01J", - "last_modified": "2023-02-17T00:02:04.034Z" - }, - { - "x": 1, - "y": 8, - "type": "TEXT", - "value": "01M", - "last_modified": "2023-02-17T00:02:04.058Z" - }, - { - "x": 1, - "y": 9, - "type": "TEXT", - "value": "02A", - "last_modified": "2023-02-17T00:02:04.080Z" - }, - { - "x": 1, - "y": 10, - "type": "TEXT", - "value": "02C", - "last_modified": "2023-02-17T00:02:04.103Z" - }, - { - "x": 1, - "y": 11, - "type": "TEXT", - "value": "02G", - "last_modified": "2023-02-17T00:02:04.125Z" - }, - { - "x": 1, - "y": 12, - "type": "TEXT", - "value": "03D", - "last_modified": "2023-02-17T00:02:04.147Z" - }, - { - "x": 1, - "y": 13, - "type": "TEXT", - "value": "04M", - "last_modified": "2023-02-17T00:02:04.169Z" - }, - { - "x": 1, - "y": 14, - "type": "TEXT", - "value": "04Y", - "last_modified": "2023-02-17T00:02:04.190Z" - }, - { - "x": 1, - "y": 15, - "type": "TEXT", - "value": "05C", - "last_modified": "2023-02-17T00:02:04.212Z" - }, - { - "x": 1, - "y": 16, - "type": "TEXT", - "value": "05F", - "last_modified": "2023-02-17T00:02:04.233Z" - }, - { - "x": 1, - "y": 17, - "type": "TEXT", - "value": "05U", - "last_modified": "2023-02-17T00:02:04.254Z" - }, - { - "x": 1, - "y": 18, - "type": "TEXT", - "value": "06A", - "last_modified": "2023-02-17T00:02:04.275Z" - }, - { - "x": 1, - "y": 19, - "type": "TEXT", - "value": "06C", - "last_modified": "2023-02-17T00:02:04.296Z" - }, - { - "x": 1, - "y": 20, - "type": "TEXT", - "value": "06D", - "last_modified": "2023-02-17T00:02:04.317Z" - }, - { - "x": 1, - "y": 21, - "type": "TEXT", - "value": "06M", - "last_modified": "2023-02-17T00:02:04.338Z" - }, - { - "x": 1, - "y": 22, - "type": "TEXT", - "value": "06N", - "last_modified": "2023-02-17T00:02:04.358Z" - }, - { - "x": 1, - "y": 23, - "type": "TEXT", - "value": "06U", - "last_modified": "2023-02-17T00:02:04.379Z" - }, - { - "x": 1, - "y": 24, - "type": "TEXT", - "value": "07C", - "last_modified": "2023-02-17T00:02:04.399Z" - }, - { - "x": 1, - "y": 25, - "type": "TEXT", - "value": "07F", - "last_modified": "2023-02-17T00:02:04.419Z" - }, - { - "x": 1, - "y": 26, - "type": "TEXT", - "value": "07G", - "last_modified": "2023-02-17T00:02:04.439Z" - }, - { - "x": 1, - "y": 27, - "type": "TEXT", - "value": "07K", - "last_modified": "2023-02-17T00:02:04.458Z" - }, - { - "x": 1, - "y": 28, - "type": "TEXT", - "value": "08A", - "last_modified": "2023-02-17T00:02:04.478Z" - }, - { - "x": 1, - "y": 29, - "type": "TEXT", - "value": "08D", - "last_modified": "2023-02-17T00:02:04.498Z" - }, - { - "x": 1, - "y": 30, - "type": "TEXT", - "value": "08K", - "last_modified": "2023-02-17T00:02:04.517Z" - }, - { - "x": 1, - "y": 31, - "type": "TEXT", - "value": "08M", - "last_modified": "2023-02-17T00:02:04.536Z" - }, - { - "x": 1, - "y": 32, - "type": "TEXT", - "value": "09A", - "last_modified": "2023-02-17T00:02:04.555Z" - }, - { - "x": 1, - "y": 33, - "type": "TEXT", - "value": "09J", - "last_modified": "2023-02-17T00:02:04.574Z" - }, - { - "x": 1, - "y": 34, - "type": "TEXT", - "value": "09K", - "last_modified": "2023-02-17T00:02:04.593Z" - }, - { - "x": 1, - "y": 35, - "type": "TEXT", - "value": "09M", - "last_modified": "2023-02-17T00:02:04.612Z" - }, - { - "x": 1, - "y": 36, - "type": "TEXT", - "value": "09W", - "last_modified": "2023-02-17T00:02:04.631Z" - }, - { - "x": 1, - "y": 37, - "type": "TEXT", - "value": "0A3", - "last_modified": "2023-02-17T00:02:04.649Z" - }, - { - "x": 1, - "y": 38, - "type": "TEXT", - "value": "0A8", - "last_modified": "2023-02-17T00:02:04.668Z" - }, - { - "x": 1, - "y": 39, - "type": "TEXT", - "value": "0A9", - "last_modified": "2023-02-17T00:02:04.686Z" - }, - { - "x": 1, - "y": 40, - "type": "TEXT", - "value": "0AK", - "last_modified": "2023-02-17T00:02:04.704Z" - }, - { - "x": 1, - "y": 41, - "type": "TEXT", - "value": "0B1", - "last_modified": "2023-02-17T00:02:04.722Z" - }, - { - "x": 1, - "y": 42, - "type": "TEXT", - "value": "0B4", - "last_modified": "2023-02-17T00:02:04.740Z" - }, - { - "x": 1, - "y": 43, - "type": "TEXT", - "value": "0B5", - "last_modified": "2023-02-17T00:02:04.758Z" - }, - { - "x": 1, - "y": 44, - "type": "TEXT", - "value": "0B7", - "last_modified": "2023-02-17T00:02:04.775Z" - }, - { - "x": 1, - "y": 45, - "type": "TEXT", - "value": "0B8", - "last_modified": "2023-02-17T00:02:04.793Z" - }, - { - "x": 1, - "y": 46, - "type": "TEXT", - "value": "0C0", - "last_modified": "2023-02-17T00:02:04.810Z" - }, - { - "x": 1, - "y": 47, - "type": "TEXT", - "value": "0C4", - "last_modified": "2023-02-17T00:02:04.828Z" - }, - { - "x": 1, - "y": 48, - "type": "TEXT", - "value": "0D1", - "last_modified": "2023-02-17T00:02:04.845Z" - }, - { - "x": 1, - "y": 49, - "type": "TEXT", - "value": "0D8", - "last_modified": "2023-02-17T00:02:04.862Z" - }, - { - "x": 1, - "y": 50, - "type": "TEXT", - "value": "0E0", - "last_modified": "2023-02-17T00:02:04.879Z" - }, - { - "x": 1, - "y": 51, - "type": "TEXT", - "value": "0E8", - "last_modified": "2023-02-17T00:02:04.896Z" - }, - { - "x": 1, - "y": 52, - "type": "TEXT", - "value": "0F2", - "last_modified": "2023-02-17T00:02:04.913Z" - }, - { - "x": 1, - "y": 53, - "type": "TEXT", - "value": "0F4", - "last_modified": "2023-02-17T00:02:04.930Z" - }, - { - "x": 1, - "y": 54, - "type": "TEXT", - "value": "0F7", - "last_modified": "2023-02-17T00:02:04.946Z" - }, - { - "x": 1, - "y": 55, - "type": "TEXT", - "value": "0F8", - "last_modified": "2023-02-17T00:02:04.963Z" - }, - { - "x": 1, - "y": 56, - "type": "TEXT", - "value": "0F9", - "last_modified": "2023-02-17T00:02:04.979Z" - }, - { - "x": 1, - "y": 57, - "type": "TEXT", - "value": "0G0", - "last_modified": "2023-02-17T00:02:04.995Z" - }, - { - "x": 1, - "y": 58, - "type": "TEXT", - "value": "0G3", - "last_modified": "2023-02-17T00:02:05.011Z" - }, - { - "x": 1, - "y": 59, - "type": "TEXT", - "value": "0G6", - "last_modified": "2023-02-17T00:02:05.027Z" - }, - { - "x": 1, - "y": 60, - "type": "TEXT", - "value": "0G7", - "last_modified": "2023-02-17T00:02:05.043Z" - }, - { - "x": 1, - "y": 61, - "type": "TEXT", - "value": "0H1", - "last_modified": "2023-02-17T00:02:05.059Z" - }, - { - "x": 1, - "y": 62, - "type": "TEXT", - "value": "0I8", - "last_modified": "2023-02-17T00:02:05.075Z" - }, - { - "x": 1, - "y": 63, - "type": "TEXT", - "value": "0J0", - "last_modified": "2023-02-17T00:02:05.090Z" - }, - { - "x": 1, - "y": 64, - "type": "TEXT", - "value": "0J4", - "last_modified": "2023-02-17T00:02:05.106Z" - }, - { - "x": 1, - "y": 65, - "type": "TEXT", - "value": "0J6", - "last_modified": "2023-02-17T00:02:05.121Z" - }, - { - "x": 1, - "y": 66, - "type": "TEXT", - "value": "0K7", - "last_modified": "2023-02-17T00:02:05.136Z" - }, - { - "x": 1, - "y": 67, - "type": "TEXT", - "value": "0L5", - "last_modified": "2023-02-17T00:02:05.152Z" - }, - { - "x": 1, - "y": 68, - "type": "TEXT", - "value": "0L7", - "last_modified": "2023-02-17T00:02:05.167Z" - }, - { - "x": 1, - "y": 69, - "type": "TEXT", - "value": "0L9", - "last_modified": "2023-02-17T00:02:05.182Z" - }, - { - "x": 1, - "y": 70, - "type": "TEXT", - "value": "0M0", - "last_modified": "2023-02-17T00:02:05.197Z" - }, - { - "x": 1, - "y": 71, - "type": "TEXT", - "value": "0M1", - "last_modified": "2023-02-17T00:02:05.211Z" - }, - { - "x": 1, - "y": 72, - "type": "TEXT", - "value": "0M4", - "last_modified": "2023-02-17T00:02:05.226Z" - }, - { - "x": 1, - "y": 73, - "type": "TEXT", - "value": "0M5", - "last_modified": "2023-02-17T00:02:05.241Z" - }, - { - "x": 1, - "y": 74, - "type": "TEXT", - "value": "0M6", - "last_modified": "2023-02-17T00:02:05.255Z" - }, - { - "x": 1, - "y": 75, - "type": "TEXT", - "value": "0M8", - "last_modified": "2023-02-17T00:02:05.270Z" - }, - { - "x": 1, - "y": 76, - "type": "TEXT", - "value": "0O3", - "last_modified": "2023-02-17T00:02:05.284Z" - }, - { - "x": 1, - "y": 77, - "type": "TEXT", - "value": "0O4", - "last_modified": "2023-02-17T00:02:05.298Z" - }, - { - "x": 1, - "y": 78, - "type": "TEXT", - "value": "0O5", - "last_modified": "2023-02-17T00:02:05.312Z" - }, - { - "x": 1, - "y": 79, - "type": "TEXT", - "value": "0Q5", - "last_modified": "2023-02-17T00:02:05.326Z" - }, - { - "x": 1, - "y": 80, - "type": "TEXT", - "value": "0Q6", - "last_modified": "2023-02-17T00:02:05.341Z" - }, - { - "x": 1, - "y": 81, - "type": "TEXT", - "value": "0R0", - "last_modified": "2023-02-17T00:02:05.355Z" - }, - { - "x": 1, - "y": 82, - "type": "TEXT", - "value": "0R1", - "last_modified": "2023-02-17T00:02:05.368Z" - }, - { - "x": 1, - "y": 83, - "type": "TEXT", - "value": "0R3", - "last_modified": "2023-02-17T00:02:05.382Z" - }, - { - "x": 1, - "y": 84, - "type": "TEXT", - "value": "0R4", - "last_modified": "2023-02-17T00:02:05.396Z" - }, - { - "x": 1, - "y": 85, - "type": "TEXT", - "value": "0R5", - "last_modified": "2023-02-17T00:02:05.410Z" - }, - { - "x": 1, - "y": 86, - "type": "TEXT", - "value": "0R7", - "last_modified": "2023-02-17T00:02:05.423Z" - }, - { - "x": 1, - "y": 87, - "type": "TEXT", - "value": "0S7", - "last_modified": "2023-02-17T00:02:05.437Z" - }, - { - "x": 1, - "y": 88, - "type": "TEXT", - "value": "0S9", - "last_modified": "2023-02-17T00:02:05.450Z" - }, - { - "x": 1, - "y": 89, - "type": "TEXT", - "value": "0V2", - "last_modified": "2023-02-17T00:02:05.463Z" - }, - { - "x": 1, - "y": 90, - "type": "TEXT", - "value": "0V3", - "last_modified": "2023-02-17T00:02:05.477Z" - }, - { - "x": 1, - "y": 91, - "type": "TEXT", - "value": "0V4", - "last_modified": "2023-02-17T00:02:05.490Z" - }, - { - "x": 1, - "y": 92, - "type": "TEXT", - "value": "0V6", - "last_modified": "2023-02-17T00:02:05.503Z" - }, - { - "x": 1, - "y": 93, - "type": "TEXT", - "value": "0V7", - "last_modified": "2023-02-17T00:02:05.516Z" - }, - { - "x": 1, - "y": 94, - "type": "TEXT", - "value": "10C", - "last_modified": "2023-02-17T00:02:05.529Z" - }, - { - "x": 1, - "y": 95, - "type": "TEXT", - "value": "10D", - "last_modified": "2023-02-17T00:02:05.542Z" - }, - { - "x": 1, - "y": 96, - "type": "TEXT", - "value": "10G", - "last_modified": "2023-02-17T00:02:05.554Z" - }, - { - "x": 1, - "y": 97, - "type": "TEXT", - "value": "10N", - "last_modified": "2023-02-17T00:02:05.567Z" - }, - { - "x": 1, - "y": 98, - "type": "TEXT", - "value": "10U", - "last_modified": "2023-02-17T00:02:05.580Z" - }, - { - "x": 1, - "y": 99, - "type": "TEXT", - "value": "11A", - "last_modified": "2023-02-17T00:02:05.592Z" - }, - { - "x": 1, - "y": 100, - "type": "TEXT", - "value": "11D", - "last_modified": "2023-02-17T00:02:05.605Z" - }, - { - "x": 1, - "y": 101, - "type": "TEXT", - "value": "11IS", - "last_modified": "2023-02-17T00:02:05.617Z" - }, - { - "x": 1, - "y": 102, - "type": "TEXT", - "value": "11J", - "last_modified": "2023-02-17T00:02:05.630Z" - }, - { - "x": 1, - "y": 103, - "type": "TEXT", - "value": "11R", - "last_modified": "2023-02-17T00:02:05.642Z" - }, - { - "x": 2, - "y": 2, - "type": "TEXT", - "value": "name" - }, - { - "x": 2, - "y": 3, - "type": "TEXT", - "value": "Thigpen", - "last_modified": "2023-02-17T00:02:03.933Z" - }, - { - "x": 2, - "y": 4, - "type": "TEXT", - "value": "Livingston Municipal", - "last_modified": "2023-02-17T00:02:03.966Z" - }, - { - "x": 2, - "y": 5, - "type": "TEXT", - "value": "Meadow Lake", - "last_modified": "2023-02-17T00:02:03.991Z" - }, - { - "x": 2, - "y": 6, - "type": "TEXT", - "value": "Perry-Warsaw", - "last_modified": "2023-02-17T00:02:04.014Z" - }, - { - "x": 2, - "y": 7, - "type": "TEXT", - "value": "Hilliard Airpark", - "last_modified": "2023-02-17T00:02:04.037Z" - }, - { - "x": 2, - "y": 8, - "type": "TEXT", - "value": "Tishomingo County", - "last_modified": "2023-02-17T00:02:04.061Z" - }, - { - "x": 2, - "y": 9, - "type": "TEXT", - "value": "Gragg-Wade", - "last_modified": "2023-02-17T00:02:04.083Z" - }, - { - "x": 2, - "y": 10, - "type": "TEXT", - "value": "Capitol", - "last_modified": "2023-02-17T00:02:04.106Z" - }, - { - "x": 2, - "y": 11, - "type": "TEXT", - "value": "Columbiana County", - "last_modified": "2023-02-17T00:02:04.128Z" - }, - { - "x": 2, - "y": 12, - "type": "TEXT", - "value": "Memphis Memorial", - "last_modified": "2023-02-17T00:02:04.150Z" - }, - { - "x": 2, - "y": 13, - "type": "TEXT", - "value": "Calhoun County", - "last_modified": "2023-02-17T00:02:04.171Z" - }, - { - "x": 2, - "y": 14, - "type": "TEXT", - "value": "Hawley Municipal", - "last_modified": "2023-02-17T00:02:04.193Z" - }, - { - "x": 2, - "y": 15, - "type": "TEXT", - "value": "Griffith-Merrillville", - "last_modified": "2023-02-17T00:02:04.214Z" - }, - { - "x": 2, - "y": 16, - "type": "TEXT", - "value": "Gatesville - City/County", - "last_modified": "2023-02-17T00:02:04.236Z" - }, - { - "x": 2, - "y": 17, - "type": "TEXT", - "value": "Eureka", - "last_modified": "2023-02-17T00:02:04.257Z" - }, - { - "x": 2, - "y": 18, - "type": "TEXT", - "value": "Moton Municipal", - "last_modified": "2023-02-17T00:02:04.278Z" - }, - { - "x": 2, - "y": 19, - "type": "TEXT", - "value": "Schaumburg", - "last_modified": "2023-02-17T00:02:04.299Z" - }, - { - "x": 2, - "y": 20, - "type": "TEXT", - "value": "Rolla Municipal", - "last_modified": "2023-02-17T00:02:04.320Z" - }, - { - "x": 2, - "y": 21, - "type": "TEXT", - "value": "Eupora Municipal", - "last_modified": "2023-02-17T00:02:04.340Z" - }, - { - "x": 2, - "y": 22, - "type": "TEXT", - "value": "Randall", - "last_modified": "2023-02-17T00:02:04.361Z" - }, - { - "x": 2, - "y": 23, - "type": "TEXT", - "value": "Jackpot/Hayden", - "last_modified": "2023-02-17T00:02:04.381Z" - }, - { - "x": 2, - "y": 24, - "type": "TEXT", - "value": "Dekalb County", - "last_modified": "2023-02-17T00:02:04.401Z" - }, - { - "x": 2, - "y": 25, - "type": "TEXT", - "value": "Gladewater Municipal", - "last_modified": "2023-02-17T00:02:04.421Z" - }, - { - "x": 2, - "y": 26, - "type": "TEXT", - "value": "Fitch H Beach", - "last_modified": "2023-02-17T00:02:04.441Z" - }, - { - "x": 2, - "y": 27, - "type": "TEXT", - "value": "Central City Municipal", - "last_modified": "2023-02-17T00:02:04.461Z" - }, - { - "x": 2, - "y": 28, - "type": "TEXT", - "value": "Wetumpka Municipal", - "last_modified": "2023-02-17T00:02:04.481Z" - }, - { - "x": 2, - "y": 29, - "type": "TEXT", - "value": "Stanley Municipal", - "last_modified": "2023-02-17T00:02:04.500Z" - }, - { - "x": 2, - "y": 30, - "type": "TEXT", - "value": "Harvard State", - "last_modified": "2023-02-17T00:02:04.519Z" - }, - { - "x": 2, - "y": 31, - "type": "TEXT", - "value": "Carthage-Leake County", - "last_modified": "2023-02-17T00:02:04.538Z" - }, - { - "x": 2, - "y": 32, - "type": "TEXT", - "value": "Butler-Choctaw County", - "last_modified": "2023-02-17T00:02:04.557Z" - }, - { - "x": 2, - "y": 33, - "type": "TEXT", - "value": "Jekyll Island", - "last_modified": "2023-02-17T00:02:04.577Z" - }, - { - "x": 2, - "y": 34, - "type": "TEXT", - "value": "Sargent Municipal", - "last_modified": "2023-02-17T00:02:04.596Z" - }, - { - "x": 2, - "y": 35, - "type": "TEXT", - "value": "Charleston Municipal", - "last_modified": "2023-02-17T00:02:04.614Z" - }, - { - "x": 2, - "y": 36, - "type": "TEXT", - "value": "South Capitol Street", - "last_modified": "2023-02-17T00:02:04.633Z" - }, - { - "x": 2, - "y": 37, - "type": "TEXT", - "value": "Smithville Municipal", - "last_modified": "2023-02-17T00:02:04.651Z" - }, - { - "x": 2, - "y": 38, - "type": "TEXT", - "value": "Bibb County", - "last_modified": "2023-02-17T00:02:04.670Z" - }, - { - "x": 2, - "y": 39, - "type": "TEXT", - "value": "Elizabethton Municipal", - "last_modified": "2023-02-17T00:02:04.688Z" - }, - { - "x": 2, - "y": 40, - "type": "TEXT", - "value": "Pilot Station", - "last_modified": "2023-02-17T00:02:04.706Z" - }, - { - "x": 2, - "y": 41, - "type": "TEXT", - "value": "Col. Dyke", - "last_modified": "2023-02-17T00:02:04.724Z" - }, - { - "x": 2, - "y": 42, - "type": "TEXT", - "value": "Hartington Municipal", - "last_modified": "2023-02-17T00:02:04.742Z" - }, - { - "x": 2, - "y": 43, - "type": "TEXT", - "value": "Turners Falls", - "last_modified": "2023-02-17T00:02:04.760Z" - }, - { - "x": 2, - "y": 44, - "type": "TEXT", - "value": "Warren-Sugar Bush", - "last_modified": "2023-02-17T00:02:04.778Z" - }, - { - "x": 2, - "y": 45, - "type": "TEXT", - "value": "Elizabeth", - "last_modified": "2023-02-17T00:02:04.795Z" - }, - { - "x": 2, - "y": 46, - "type": "TEXT", - "value": "Dacy", - "last_modified": "2023-02-17T00:02:04.812Z" - }, - { - "x": 2, - "y": 47, - "type": "TEXT", - "value": "Pender Municipal", - "last_modified": "2023-02-17T00:02:04.830Z" - }, - { - "x": 2, - "y": 48, - "type": "TEXT", - "value": "South Haven Municipal", - "last_modified": "2023-02-17T00:02:04.847Z" - }, - { - "x": 2, - "y": 49, - "type": "TEXT", - "value": "Gettysburg Municipal", - "last_modified": "2023-02-17T00:02:04.864Z" - }, - { - "x": 2, - "y": 50, - "type": "TEXT", - "value": "Moriarty", - "last_modified": "2023-02-17T00:02:04.881Z" - }, - { - "x": 2, - "y": 51, - "type": "TEXT", - "value": "Crownpoint", - "last_modified": "2023-02-17T00:02:04.899Z" - }, - { - "x": 2, - "y": 52, - "type": "TEXT", - "value": "Bowie Municipal", - "last_modified": "2023-02-17T00:02:04.915Z" - }, - { - "x": 2, - "y": 53, - "type": "TEXT", - "value": "Loup City Municipal", - "last_modified": "2023-02-17T00:02:04.932Z" - }, - { - "x": 2, - "y": 54, - "type": "TEXT", - "value": "Fountainhead Lodge Airpark", - "last_modified": "2023-02-17T00:02:04.948Z" - }, - { - "x": 2, - "y": 55, - "type": "TEXT", - "value": "William R Pogue Municipal", - "last_modified": "2023-02-17T00:02:04.965Z" - }, - { - "x": 2, - "y": 56, - "type": "TEXT", - "value": "Tishomingo Airpark", - "last_modified": "2023-02-17T00:02:04.981Z" - }, - { - "x": 2, - "y": 57, - "type": "TEXT", - "value": "North Buffalo Suburban", - "last_modified": "2023-02-17T00:02:04.997Z" - }, - { - "x": 2, - "y": 58, - "type": "TEXT", - "value": "Tecumseh Municipal", - "last_modified": "2023-02-17T00:02:05.013Z" - }, - { - "x": 2, - "y": 59, - "type": "TEXT", - "value": "Williams County", - "last_modified": "2023-02-17T00:02:05.029Z" - }, - { - "x": 2, - "y": 60, - "type": "TEXT", - "value": "Finger Lakes Regional", - "last_modified": "2023-02-17T00:02:05.045Z" - }, - { - "x": 2, - "y": 61, - "type": "TEXT", - "value": "Trego Wakeeney", - "last_modified": "2023-02-17T00:02:05.061Z" - }, - { - "x": 2, - "y": 62, - "type": "TEXT", - "value": "Cynthiana-Harrison County", - "last_modified": "2023-02-17T00:02:05.077Z" - }, - { - "x": 2, - "y": 63, - "type": "TEXT", - "value": "Abbeville Municipal", - "last_modified": "2023-02-17T00:02:05.092Z" - }, - { - "x": 2, - "y": 64, - "type": "TEXT", - "value": "Florala Municipal", - "last_modified": "2023-02-17T00:02:05.108Z" - }, - { - "x": 2, - "y": 65, - "type": "TEXT", - "value": "Headland Municipal", - "last_modified": "2023-02-17T00:02:05.123Z" - }, - { - "x": 2, - "y": 66, - "type": "TEXT", - "value": "Humboldt Municipal", - "last_modified": "2023-02-17T00:02:05.138Z" - }, - { - "x": 2, - "y": 67, - "type": "TEXT", - "value": "Goldfield", - "last_modified": "2023-02-17T00:02:05.153Z" - }, - { - "x": 2, - "y": 68, - "type": "TEXT", - "value": "Jean", - "last_modified": "2023-02-17T00:02:05.169Z" - }, - { - "x": 2, - "y": 69, - "type": "TEXT", - "value": "Echo Bay", - "last_modified": "2023-02-17T00:02:05.184Z" - }, - { - "x": 2, - "y": 70, - "type": "TEXT", - "value": "Dumas Municipal", - "last_modified": "2023-02-17T00:02:05.198Z" - }, - { - "x": 2, - "y": 71, - "type": "TEXT", - "value": "Scott", - "last_modified": "2023-02-17T00:02:05.213Z" - }, - { - "x": 2, - "y": 72, - "type": "TEXT", - "value": "Benton County", - "last_modified": "2023-02-17T00:02:05.228Z" - }, - { - "x": 2, - "y": 73, - "type": "TEXT", - "value": "Humphreys County", - "last_modified": "2023-02-17T00:02:05.243Z" - }, - { - "x": 2, - "y": 74, - "type": "TEXT", - "value": "Panola County", - "last_modified": "2023-02-17T00:02:05.257Z" - }, - { - "x": 2, - "y": 75, - "type": "TEXT", - "value": "Byerley", - "last_modified": "2023-02-17T00:02:05.272Z" - }, - { - "x": 2, - "y": 76, - "type": "TEXT", - "value": "Calaveras Co-Maury Rasmussen", - "last_modified": "2023-02-17T00:02:05.286Z" - }, - { - "x": 2, - "y": 77, - "type": "TEXT", - "value": "Corning Municipal", - "last_modified": "2023-02-17T00:02:05.300Z" - }, - { - "x": 2, - "y": 78, - "type": "TEXT", - "value": "University", - "last_modified": "2023-02-17T00:02:05.314Z" - }, - { - "x": 2, - "y": 79, - "type": "TEXT", - "value": "Shelter Cove", - "last_modified": "2023-02-17T00:02:05.328Z" - }, - { - "x": 2, - "y": 80, - "type": "TEXT", - "value": "Shingletown", - "last_modified": "2023-02-17T00:02:05.342Z" - }, - { - "x": 2, - "y": 81, - "type": "TEXT", - "value": "Columbia-Marion County", - "last_modified": "2023-02-17T00:02:05.356Z" - }, - { - "x": 2, - "y": 82, - "type": "TEXT", - "value": "Atmore Municipal", - "last_modified": "2023-02-17T00:02:05.370Z" - }, - { - "x": 2, - "y": 83, - "type": "TEXT", - "value": "Abbeville Chris Crusta Memorial", - "last_modified": "2023-02-17T00:02:05.384Z" - }, - { - "x": 2, - "y": 84, - "type": "TEXT", - "value": "Concordia Parish", - "last_modified": "2023-02-17T00:02:05.398Z" - }, - { - "x": 2, - "y": 85, - "type": "TEXT", - "value": "David G Joyce", - "last_modified": "2023-02-17T00:02:05.412Z" - }, - { - "x": 2, - "y": 86, - "type": "TEXT", - "value": "Red River", - "last_modified": "2023-02-17T00:02:05.425Z" - }, - { - "x": 2, - "y": 87, - "type": "TEXT", - "value": "Dorothy Scott", - "last_modified": "2023-02-17T00:02:05.438Z" - }, - { - "x": 2, - "y": 88, - "type": "TEXT", - "value": "Jefferson County International", - "last_modified": "2023-02-17T00:02:05.452Z" - }, - { - "x": 2, - "y": 89, - "type": "TEXT", - "value": "Harriet Alexander", - "last_modified": "2023-02-17T00:02:05.465Z" - }, - { - "x": 2, - "y": 90, - "type": "TEXT", - "value": "Pioneer Village", - "last_modified": "2023-02-17T00:02:05.478Z" - }, - { - "x": 2, - "y": 91, - "type": "TEXT", - "value": "Brookneal/Campbell County", - "last_modified": "2023-02-17T00:02:05.491Z" - }, - { - "x": 2, - "y": 92, - "type": "TEXT", - "value": "Mission Sioux", - "last_modified": "2023-02-17T00:02:05.504Z" - }, - { - "x": 2, - "y": 93, - "type": "TEXT", - "value": "Kayenta", - "last_modified": "2023-02-17T00:02:05.517Z" - }, - { - "x": 2, - "y": 94, - "type": "TEXT", - "value": "Galt", - "last_modified": "2023-02-17T00:02:05.530Z" - }, - { - "x": 2, - "y": 95, - "type": "TEXT", - "value": "Winsted Municipal", - "last_modified": "2023-02-17T00:02:05.543Z" - }, - { - "x": 2, - "y": 96, - "type": "TEXT", - "value": "Holmes County", - "last_modified": "2023-02-17T00:02:05.556Z" - }, - { - "x": 2, - "y": 97, - "type": "TEXT", - "value": "Wallkill", - "last_modified": "2023-02-17T00:02:05.569Z" - }, - { - "x": 2, - "y": 98, - "type": "TEXT", - "value": "Owyhee", - "last_modified": "2023-02-17T00:02:05.581Z" - }, - { - "x": 2, - "y": 99, - "type": "TEXT", - "value": "Clayton Municipal", - "last_modified": "2023-02-17T00:02:05.594Z" - }, - { - "x": 2, - "y": 100, - "type": "TEXT", - "value": "Clarion Cty", - "last_modified": "2023-02-17T00:02:05.606Z" - }, - { - "x": 2, - "y": 101, - "type": "TEXT", - "value": "Schaumburg Heliport", - "last_modified": "2023-02-17T00:02:05.619Z" - }, - { - "x": 2, - "y": 102, - "type": "TEXT", - "value": "Early County", - "last_modified": "2023-02-17T00:02:05.631Z" - }, - { - "x": 2, - "y": 103, - "type": "TEXT", - "value": "Brenham Municipal", - "last_modified": "2023-02-17T00:02:05.643Z" - }, - { - "x": 3, - "y": 2, - "type": "TEXT", - "value": "city", - "last_modified": "2023-02-16T23:48:40.740Z" - }, - { - "x": 4, - "y": 2, - "type": "TEXT", - "value": "state", - "last_modified": "2023-02-16T23:48:40.741Z" - }, - { - "x": 5, - "y": 2, - "type": "TEXT", - "value": "country", - "last_modified": "2023-02-16T23:48:40.741Z" - }, - { - "x": 6, - "y": 2, - "type": "TEXT", - "value": "latitude", - "last_modified": "2023-02-16T23:48:40.742Z" - }, - { - "x": 7, - "y": 2, - "type": "TEXT", - "value": "longitude", - "last_modified": "2023-02-16T23:48:40.743Z" - }, - { - "x": 3, - "y": 3, - "type": "TEXT", - "value": "Bay Springs", - "last_modified": "2023-02-17T00:02:03.938Z" - }, - { - "x": 4, - "y": 3, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:03.943Z" - }, - { - "x": 5, - "y": 3, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:03.947Z" - }, - { - "x": 6, - "y": 3, - "type": "TEXT", - "value": "31.95376472", - "last_modified": "2023-02-17T00:02:03.951Z" - }, - { - "x": 7, - "y": 3, - "type": "TEXT", - "value": "-89.23450472", - "last_modified": "2023-02-17T00:02:03.955Z" - }, - { - "x": 3, - "y": 4, - "type": "TEXT", - "value": "Livingston", - "last_modified": "2023-02-17T00:02:03.969Z" - }, - { - "x": 4, - "y": 4, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:03.972Z" - }, - { - "x": 5, - "y": 4, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:03.976Z" - }, - { - "x": 6, - "y": 4, - "type": "TEXT", - "value": "30.68586111", - "last_modified": "2023-02-17T00:02:03.979Z" - }, - { - "x": 7, - "y": 4, - "type": "TEXT", - "value": "-95.01792778", - "last_modified": "2023-02-17T00:02:03.982Z" - }, - { - "x": 3, - "y": 5, - "type": "TEXT", - "value": "Colorado Springs", - "last_modified": "2023-02-17T00:02:03.994Z" - }, - { - "x": 4, - "y": 5, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:03.997Z" - }, - { - "x": 5, - "y": 5, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.000Z" - }, - { - "x": 6, - "y": 5, - "type": "TEXT", - "value": "38.94574889", - "last_modified": "2023-02-17T00:02:04.003Z" - }, - { - "x": 7, - "y": 5, - "type": "TEXT", - "value": "-104.5698933", - "last_modified": "2023-02-17T00:02:04.006Z" - }, - { - "x": 3, - "y": 6, - "type": "TEXT", - "value": "Perry", - "last_modified": "2023-02-17T00:02:04.017Z" - }, - { - "x": 4, - "y": 6, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:04.020Z" - }, - { - "x": 5, - "y": 6, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.023Z" - }, - { - "x": 6, - "y": 6, - "type": "TEXT", - "value": "42.74134667", - "last_modified": "2023-02-17T00:02:04.026Z" - }, - { - "x": 7, - "y": 6, - "type": "TEXT", - "value": "-78.05208056", - "last_modified": "2023-02-17T00:02:04.029Z" - }, - { - "x": 3, - "y": 7, - "type": "TEXT", - "value": "Hilliard", - "last_modified": "2023-02-17T00:02:04.040Z" - }, - { - "x": 4, - "y": 7, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:04.043Z" - }, - { - "x": 5, - "y": 7, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.046Z" - }, - { - "x": 6, - "y": 7, - "type": "TEXT", - "value": "30.6880125", - "last_modified": "2023-02-17T00:02:04.049Z" - }, - { - "x": 7, - "y": 7, - "type": "TEXT", - "value": "-81.90594389", - "last_modified": "2023-02-17T00:02:04.052Z" - }, - { - "x": 3, - "y": 8, - "type": "TEXT", - "value": "Belmont", - "last_modified": "2023-02-17T00:02:04.064Z" - }, - { - "x": 4, - "y": 8, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:04.066Z" - }, - { - "x": 5, - "y": 8, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.069Z" - }, - { - "x": 6, - "y": 8, - "type": "TEXT", - "value": "34.49166667", - "last_modified": "2023-02-17T00:02:04.072Z" - }, - { - "x": 7, - "y": 8, - "type": "TEXT", - "value": "-88.20111111", - "last_modified": "2023-02-17T00:02:04.075Z" - }, - { - "x": 3, - "y": 9, - "type": "TEXT", - "value": "Clanton", - "last_modified": "2023-02-17T00:02:04.086Z" - }, - { - "x": 4, - "y": 9, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:04.089Z" - }, - { - "x": 5, - "y": 9, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.091Z" - }, - { - "x": 6, - "y": 9, - "type": "TEXT", - "value": "32.85048667", - "last_modified": "2023-02-17T00:02:04.095Z" - }, - { - "x": 7, - "y": 9, - "type": "TEXT", - "value": "-86.61145333", - "last_modified": "2023-02-17T00:02:04.097Z" - }, - { - "x": 3, - "y": 10, - "type": "TEXT", - "value": "Brookfield", - "last_modified": "2023-02-17T00:02:04.109Z" - }, - { - "x": 4, - "y": 10, - "type": "TEXT", - "value": "WI", - "last_modified": "2023-02-17T00:02:04.111Z" - }, - { - "x": 5, - "y": 10, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.114Z" - }, - { - "x": 6, - "y": 10, - "type": "TEXT", - "value": "43.08751", - "last_modified": "2023-02-17T00:02:04.117Z" - }, - { - "x": 7, - "y": 10, - "type": "TEXT", - "value": "-88.17786917", - "last_modified": "2023-02-17T00:02:04.120Z" - }, - { - "x": 3, - "y": 11, - "type": "TEXT", - "value": "East Liverpool", - "last_modified": "2023-02-17T00:02:04.131Z" - }, - { - "x": 4, - "y": 11, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:04.133Z" - }, - { - "x": 5, - "y": 11, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.136Z" - }, - { - "x": 6, - "y": 11, - "type": "TEXT", - "value": "40.67331278", - "last_modified": "2023-02-17T00:02:04.139Z" - }, - { - "x": 7, - "y": 11, - "type": "TEXT", - "value": "-80.64140639", - "last_modified": "2023-02-17T00:02:04.142Z" - }, - { - "x": 3, - "y": 12, - "type": "TEXT", - "value": "Memphis", - "last_modified": "2023-02-17T00:02:04.152Z" - }, - { - "x": 4, - "y": 12, - "type": "TEXT", - "value": "MO", - "last_modified": "2023-02-17T00:02:04.155Z" - }, - { - "x": 5, - "y": 12, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.158Z" - }, - { - "x": 6, - "y": 12, - "type": "TEXT", - "value": "40.44725889", - "last_modified": "2023-02-17T00:02:04.161Z" - }, - { - "x": 7, - "y": 12, - "type": "TEXT", - "value": "-92.22696056", - "last_modified": "2023-02-17T00:02:04.163Z" - }, - { - "x": 3, - "y": 13, - "type": "TEXT", - "value": "Pittsboro", - "last_modified": "2023-02-17T00:02:04.174Z" - }, - { - "x": 4, - "y": 13, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:04.177Z" - }, - { - "x": 5, - "y": 13, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.180Z" - }, - { - "x": 6, - "y": 13, - "type": "TEXT", - "value": "33.93011222", - "last_modified": "2023-02-17T00:02:04.182Z" - }, - { - "x": 7, - "y": 13, - "type": "TEXT", - "value": "-89.34285194", - "last_modified": "2023-02-17T00:02:04.185Z" - }, - { - "x": 3, - "y": 14, - "type": "TEXT", - "value": "Hawley", - "last_modified": "2023-02-17T00:02:04.196Z" - }, - { - "x": 4, - "y": 14, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:04.198Z" - }, - { - "x": 5, - "y": 14, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.201Z" - }, - { - "x": 6, - "y": 14, - "type": "TEXT", - "value": "46.88384889", - "last_modified": "2023-02-17T00:02:04.204Z" - }, - { - "x": 7, - "y": 14, - "type": "TEXT", - "value": "-96.35089861", - "last_modified": "2023-02-17T00:02:04.206Z" - }, - { - "x": 3, - "y": 15, - "type": "TEXT", - "value": "Griffith", - "last_modified": "2023-02-17T00:02:04.217Z" - }, - { - "x": 4, - "y": 15, - "type": "TEXT", - "value": "IN", - "last_modified": "2023-02-17T00:02:04.220Z" - }, - { - "x": 5, - "y": 15, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.222Z" - }, - { - "x": 6, - "y": 15, - "type": "TEXT", - "value": "41.51961917", - "last_modified": "2023-02-17T00:02:04.225Z" - }, - { - "x": 7, - "y": 15, - "type": "TEXT", - "value": "-87.40109333", - "last_modified": "2023-02-17T00:02:04.228Z" - }, - { - "x": 3, - "y": 16, - "type": "TEXT", - "value": "Gatesville", - "last_modified": "2023-02-17T00:02:04.238Z" - }, - { - "x": 4, - "y": 16, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:04.241Z" - }, - { - "x": 5, - "y": 16, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.244Z" - }, - { - "x": 6, - "y": 16, - "type": "TEXT", - "value": "31.42127556", - "last_modified": "2023-02-17T00:02:04.246Z" - }, - { - "x": 7, - "y": 16, - "type": "TEXT", - "value": "-97.79696778", - "last_modified": "2023-02-17T00:02:04.249Z" - }, - { - "x": 3, - "y": 17, - "type": "TEXT", - "value": "Eureka", - "last_modified": "2023-02-17T00:02:04.260Z" - }, - { - "x": 4, - "y": 17, - "type": "TEXT", - "value": "NV", - "last_modified": "2023-02-17T00:02:04.262Z" - }, - { - "x": 5, - "y": 17, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.265Z" - }, - { - "x": 6, - "y": 17, - "type": "TEXT", - "value": "39.60416667", - "last_modified": "2023-02-17T00:02:04.268Z" - }, - { - "x": 7, - "y": 17, - "type": "TEXT", - "value": "-116.0050597", - "last_modified": "2023-02-17T00:02:04.270Z" - }, - { - "x": 3, - "y": 18, - "type": "TEXT", - "value": "Tuskegee", - "last_modified": "2023-02-17T00:02:04.281Z" - }, - { - "x": 4, - "y": 18, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:04.283Z" - }, - { - "x": 5, - "y": 18, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.286Z" - }, - { - "x": 6, - "y": 18, - "type": "TEXT", - "value": "32.46047167", - "last_modified": "2023-02-17T00:02:04.289Z" - }, - { - "x": 7, - "y": 18, - "type": "TEXT", - "value": "-85.68003611", - "last_modified": "2023-02-17T00:02:04.291Z" - }, - { - "x": 3, - "y": 19, - "type": "TEXT", - "value": "Chicago/Schaumburg", - "last_modified": "2023-02-17T00:02:04.302Z" - }, - { - "x": 4, - "y": 19, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:04.304Z" - }, - { - "x": 5, - "y": 19, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.307Z" - }, - { - "x": 6, - "y": 19, - "type": "TEXT", - "value": "41.98934083", - "last_modified": "2023-02-17T00:02:04.309Z" - }, - { - "x": 7, - "y": 19, - "type": "TEXT", - "value": "-88.10124278", - "last_modified": "2023-02-17T00:02:04.312Z" - }, - { - "x": 3, - "y": 20, - "type": "TEXT", - "value": "Rolla", - "last_modified": "2023-02-17T00:02:04.322Z" - }, - { - "x": 4, - "y": 20, - "type": "TEXT", - "value": "ND", - "last_modified": "2023-02-17T00:02:04.325Z" - }, - { - "x": 5, - "y": 20, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.327Z" - }, - { - "x": 6, - "y": 20, - "type": "TEXT", - "value": "48.88434111", - "last_modified": "2023-02-17T00:02:04.330Z" - }, - { - "x": 7, - "y": 20, - "type": "TEXT", - "value": "-99.62087694", - "last_modified": "2023-02-17T00:02:04.332Z" - }, - { - "x": 3, - "y": 21, - "type": "TEXT", - "value": "Eupora", - "last_modified": "2023-02-17T00:02:04.343Z" - }, - { - "x": 4, - "y": 21, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:04.345Z" - }, - { - "x": 5, - "y": 21, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.348Z" - }, - { - "x": 6, - "y": 21, - "type": "TEXT", - "value": "33.53456583", - "last_modified": "2023-02-17T00:02:04.350Z" - }, - { - "x": 7, - "y": 21, - "type": "TEXT", - "value": "-89.31256917", - "last_modified": "2023-02-17T00:02:04.353Z" - }, - { - "x": 3, - "y": 22, - "type": "TEXT", - "value": "Middletown", - "last_modified": "2023-02-17T00:02:04.363Z" - }, - { - "x": 4, - "y": 22, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:04.366Z" - }, - { - "x": 5, - "y": 22, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.368Z" - }, - { - "x": 6, - "y": 22, - "type": "TEXT", - "value": "41.43156583", - "last_modified": "2023-02-17T00:02:04.371Z" - }, - { - "x": 7, - "y": 22, - "type": "TEXT", - "value": "-74.39191722", - "last_modified": "2023-02-17T00:02:04.373Z" - }, - { - "x": 3, - "y": 23, - "type": "TEXT", - "value": "Jackpot", - "last_modified": "2023-02-17T00:02:04.384Z" - }, - { - "x": 4, - "y": 23, - "type": "TEXT", - "value": "NV", - "last_modified": "2023-02-17T00:02:04.386Z" - }, - { - "x": 5, - "y": 23, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.389Z" - }, - { - "x": 6, - "y": 23, - "type": "TEXT", - "value": "41.97602222", - "last_modified": "2023-02-17T00:02:04.391Z" - }, - { - "x": 7, - "y": 23, - "type": "TEXT", - "value": "-114.6580911", - "last_modified": "2023-02-17T00:02:04.394Z" - }, - { - "x": 3, - "y": 24, - "type": "TEXT", - "value": "Auburn", - "last_modified": "2023-02-17T00:02:04.404Z" - }, - { - "x": 4, - "y": 24, - "type": "TEXT", - "value": "IN", - "last_modified": "2023-02-17T00:02:04.406Z" - }, - { - "x": 5, - "y": 24, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.409Z" - }, - { - "x": 6, - "y": 24, - "type": "TEXT", - "value": "41.30716667", - "last_modified": "2023-02-17T00:02:04.411Z" - }, - { - "x": 7, - "y": 24, - "type": "TEXT", - "value": "-85.06433333", - "last_modified": "2023-02-17T00:02:04.414Z" - }, - { - "x": 3, - "y": 25, - "type": "TEXT", - "value": "Gladewater", - "last_modified": "2023-02-17T00:02:04.424Z" - }, - { - "x": 4, - "y": 25, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:04.426Z" - }, - { - "x": 5, - "y": 25, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.429Z" - }, - { - "x": 6, - "y": 25, - "type": "TEXT", - "value": "32.52883861", - "last_modified": "2023-02-17T00:02:04.431Z" - }, - { - "x": 7, - "y": 25, - "type": "TEXT", - "value": "-94.97174556", - "last_modified": "2023-02-17T00:02:04.434Z" - }, - { - "x": 3, - "y": 26, - "type": "TEXT", - "value": "Charlotte", - "last_modified": "2023-02-17T00:02:04.444Z" - }, - { - "x": 4, - "y": 26, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:04.446Z" - }, - { - "x": 5, - "y": 26, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.449Z" - }, - { - "x": 6, - "y": 26, - "type": "TEXT", - "value": "42.57450861", - "last_modified": "2023-02-17T00:02:04.451Z" - }, - { - "x": 7, - "y": 26, - "type": "TEXT", - "value": "-84.81143139", - "last_modified": "2023-02-17T00:02:04.454Z" - }, - { - "x": 3, - "y": 27, - "type": "TEXT", - "value": "Central City", - "last_modified": "2023-02-17T00:02:04.463Z" - }, - { - "x": 4, - "y": 27, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:04.466Z" - }, - { - "x": 5, - "y": 27, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.468Z" - }, - { - "x": 6, - "y": 27, - "type": "TEXT", - "value": "41.11668056", - "last_modified": "2023-02-17T00:02:04.471Z" - }, - { - "x": 7, - "y": 27, - "type": "TEXT", - "value": "-98.05033639", - "last_modified": "2023-02-17T00:02:04.473Z" - }, - { - "x": 3, - "y": 28, - "type": "TEXT", - "value": "Wetumpka", - "last_modified": "2023-02-17T00:02:04.483Z" - }, - { - "x": 4, - "y": 28, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:04.485Z" - }, - { - "x": 5, - "y": 28, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.488Z" - }, - { - "x": 6, - "y": 28, - "type": "TEXT", - "value": "32.52943944", - "last_modified": "2023-02-17T00:02:04.490Z" - }, - { - "x": 7, - "y": 28, - "type": "TEXT", - "value": "-86.32822139", - "last_modified": "2023-02-17T00:02:04.493Z" - }, - { - "x": 3, - "y": 29, - "type": "TEXT", - "value": "Stanley", - "last_modified": "2023-02-17T00:02:04.502Z" - }, - { - "x": 4, - "y": 29, - "type": "TEXT", - "value": "ND", - "last_modified": "2023-02-17T00:02:04.505Z" - }, - { - "x": 5, - "y": 29, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.507Z" - }, - { - "x": 6, - "y": 29, - "type": "TEXT", - "value": "48.30079861", - "last_modified": "2023-02-17T00:02:04.510Z" - }, - { - "x": 7, - "y": 29, - "type": "TEXT", - "value": "-102.4063514", - "last_modified": "2023-02-17T00:02:04.512Z" - }, - { - "x": 3, - "y": 30, - "type": "TEXT", - "value": "Harvard", - "last_modified": "2023-02-17T00:02:04.522Z" - }, - { - "x": 4, - "y": 30, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:04.524Z" - }, - { - "x": 5, - "y": 30, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.526Z" - }, - { - "x": 6, - "y": 30, - "type": "TEXT", - "value": "40.65138528", - "last_modified": "2023-02-17T00:02:04.529Z" - }, - { - "x": 7, - "y": 30, - "type": "TEXT", - "value": "-98.07978667", - "last_modified": "2023-02-17T00:02:04.531Z" - }, - { - "x": 3, - "y": 31, - "type": "TEXT", - "value": "Carthage", - "last_modified": "2023-02-17T00:02:04.541Z" - }, - { - "x": 4, - "y": 31, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:04.543Z" - }, - { - "x": 5, - "y": 31, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.546Z" - }, - { - "x": 6, - "y": 31, - "type": "TEXT", - "value": "32.76124611", - "last_modified": "2023-02-17T00:02:04.548Z" - }, - { - "x": 7, - "y": 31, - "type": "TEXT", - "value": "-89.53007139", - "last_modified": "2023-02-17T00:02:04.550Z" - }, - { - "x": 3, - "y": 32, - "type": "TEXT", - "value": "Butler", - "last_modified": "2023-02-17T00:02:04.560Z" - }, - { - "x": 4, - "y": 32, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:04.562Z" - }, - { - "x": 5, - "y": 32, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.565Z" - }, - { - "x": 6, - "y": 32, - "type": "TEXT", - "value": "32.11931306", - "last_modified": "2023-02-17T00:02:04.567Z" - }, - { - "x": 7, - "y": 32, - "type": "TEXT", - "value": "-88.1274625", - "last_modified": "2023-02-17T00:02:04.569Z" - }, - { - "x": 3, - "y": 33, - "type": "TEXT", - "value": "Jekyll Island", - "last_modified": "2023-02-17T00:02:04.579Z" - }, - { - "x": 4, - "y": 33, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:04.581Z" - }, - { - "x": 5, - "y": 33, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.584Z" - }, - { - "x": 6, - "y": 33, - "type": "TEXT", - "value": "31.07447222", - "last_modified": "2023-02-17T00:02:04.586Z" - }, - { - "x": 7, - "y": 33, - "type": "TEXT", - "value": "-81.42777778", - "last_modified": "2023-02-17T00:02:04.588Z" - }, - { - "x": 3, - "y": 34, - "type": "TEXT", - "value": "Sargent", - "last_modified": "2023-02-17T00:02:04.598Z" - }, - { - "x": 4, - "y": 34, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:04.600Z" - }, - { - "x": 5, - "y": 34, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.603Z" - }, - { - "x": 6, - "y": 34, - "type": "TEXT", - "value": "41.63695083", - "last_modified": "2023-02-17T00:02:04.605Z" - }, - { - "x": 7, - "y": 34, - "type": "TEXT", - "value": "-99.34038139", - "last_modified": "2023-02-17T00:02:04.607Z" - }, - { - "x": 3, - "y": 35, - "type": "TEXT", - "value": "Charleston", - "last_modified": "2023-02-17T00:02:04.617Z" - }, - { - "x": 4, - "y": 35, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:04.619Z" - }, - { - "x": 5, - "y": 35, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.621Z" - }, - { - "x": 6, - "y": 35, - "type": "TEXT", - "value": "33.99150222", - "last_modified": "2023-02-17T00:02:04.624Z" - }, - { - "x": 7, - "y": 35, - "type": "TEXT", - "value": "-90.078145", - "last_modified": "2023-02-17T00:02:04.626Z" - }, - { - "x": 3, - "y": 36, - "type": "TEXT", - "value": "Washington", - "last_modified": "2023-02-17T00:02:04.635Z" - }, - { - "x": 4, - "y": 36, - "type": "TEXT", - "value": "DC", - "last_modified": "2023-02-17T00:02:04.638Z" - }, - { - "x": 5, - "y": 36, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.640Z" - }, - { - "x": 6, - "y": 36, - "type": "TEXT", - "value": "38.86872333", - "last_modified": "2023-02-17T00:02:04.642Z" - }, - { - "x": 7, - "y": 36, - "type": "TEXT", - "value": "-77.00747583", - "last_modified": "2023-02-17T00:02:04.645Z" - }, - { - "x": 3, - "y": 37, - "type": "TEXT", - "value": "Smithville", - "last_modified": "2023-02-17T00:02:04.654Z" - }, - { - "x": 4, - "y": 37, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:04.656Z" - }, - { - "x": 5, - "y": 37, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.658Z" - }, - { - "x": 6, - "y": 37, - "type": "TEXT", - "value": "35.98531194", - "last_modified": "2023-02-17T00:02:04.661Z" - }, - { - "x": 7, - "y": 37, - "type": "TEXT", - "value": "-85.80931806", - "last_modified": "2023-02-17T00:02:04.663Z" - }, - { - "x": 3, - "y": 38, - "type": "TEXT", - "value": "Centreville", - "last_modified": "2023-02-17T00:02:04.672Z" - }, - { - "x": 4, - "y": 38, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:04.674Z" - }, - { - "x": 5, - "y": 38, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.677Z" - }, - { - "x": 6, - "y": 38, - "type": "TEXT", - "value": "32.93679056", - "last_modified": "2023-02-17T00:02:04.679Z" - }, - { - "x": 7, - "y": 38, - "type": "TEXT", - "value": "-87.08888306", - "last_modified": "2023-02-17T00:02:04.681Z" - }, - { - "x": 3, - "y": 39, - "type": "TEXT", - "value": "Elizabethton", - "last_modified": "2023-02-17T00:02:04.690Z" - }, - { - "x": 4, - "y": 39, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:04.693Z" - }, - { - "x": 5, - "y": 39, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.695Z" - }, - { - "x": 6, - "y": 39, - "type": "TEXT", - "value": "36.37094306", - "last_modified": "2023-02-17T00:02:04.697Z" - }, - { - "x": 7, - "y": 39, - "type": "TEXT", - "value": "-82.17374111", - "last_modified": "2023-02-17T00:02:04.699Z" - }, - { - "x": 3, - "y": 40, - "type": "TEXT", - "value": "Pilot Station", - "last_modified": "2023-02-17T00:02:04.708Z" - }, - { - "x": 4, - "y": 40, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:04.711Z" - }, - { - "x": 5, - "y": 40, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.713Z" - }, - { - "x": 6, - "y": 40, - "type": "TEXT", - "value": "61.93396417", - "last_modified": "2023-02-17T00:02:04.715Z" - }, - { - "x": 7, - "y": 40, - "type": "TEXT", - "value": "-162.8929358", - "last_modified": "2023-02-17T00:02:04.717Z" - }, - { - "x": 3, - "y": 41, - "type": "TEXT", - "value": "Bethel", - "last_modified": "2023-02-17T00:02:04.727Z" - }, - { - "x": 4, - "y": 41, - "type": "TEXT", - "value": "ME", - "last_modified": "2023-02-17T00:02:04.729Z" - }, - { - "x": 5, - "y": 41, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.731Z" - }, - { - "x": 6, - "y": 41, - "type": "TEXT", - "value": "44.42506444", - "last_modified": "2023-02-17T00:02:04.733Z" - }, - { - "x": 7, - "y": 41, - "type": "TEXT", - "value": "-70.80784778", - "last_modified": "2023-02-17T00:02:04.735Z" - }, - { - "x": 3, - "y": 42, - "type": "TEXT", - "value": "Hartington", - "last_modified": "2023-02-17T00:02:04.744Z" - }, - { - "x": 4, - "y": 42, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:04.747Z" - }, - { - "x": 5, - "y": 42, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.749Z" - }, - { - "x": 6, - "y": 42, - "type": "TEXT", - "value": "42.60355556", - "last_modified": "2023-02-17T00:02:04.751Z" - }, - { - "x": 7, - "y": 42, - "type": "TEXT", - "value": "-97.25263889", - "last_modified": "2023-02-17T00:02:04.753Z" - }, - { - "x": 3, - "y": 43, - "type": "TEXT", - "value": "Montague", - "last_modified": "2023-02-17T00:02:04.762Z" - }, - { - "x": 4, - "y": 43, - "type": "TEXT", - "value": "MA", - "last_modified": "2023-02-17T00:02:04.764Z" - }, - { - "x": 5, - "y": 43, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.767Z" - }, - { - "x": 6, - "y": 43, - "type": "TEXT", - "value": "42.59136361", - "last_modified": "2023-02-17T00:02:04.769Z" - }, - { - "x": 7, - "y": 43, - "type": "TEXT", - "value": "-72.52275472", - "last_modified": "2023-02-17T00:02:04.771Z" - }, - { - "x": 3, - "y": 44, - "type": "TEXT", - "value": "Warren", - "last_modified": "2023-02-17T00:02:04.780Z" - }, - { - "x": 4, - "y": 44, - "type": "TEXT", - "value": "VT", - "last_modified": "2023-02-17T00:02:04.782Z" - }, - { - "x": 5, - "y": 44, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.784Z" - }, - { - "x": 6, - "y": 44, - "type": "TEXT", - "value": "44.11672722", - "last_modified": "2023-02-17T00:02:04.786Z" - }, - { - "x": 7, - "y": 44, - "type": "TEXT", - "value": "-72.82705806", - "last_modified": "2023-02-17T00:02:04.789Z" - }, - { - "x": 3, - "y": 45, - "type": "TEXT", - "value": "Fishers Island", - "last_modified": "2023-02-17T00:02:04.797Z" - }, - { - "x": 4, - "y": 45, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:04.799Z" - }, - { - "x": 5, - "y": 45, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.802Z" - }, - { - "x": 6, - "y": 45, - "type": "TEXT", - "value": "41.25130806", - "last_modified": "2023-02-17T00:02:04.804Z" - }, - { - "x": 7, - "y": 45, - "type": "TEXT", - "value": "-72.03161139", - "last_modified": "2023-02-17T00:02:04.806Z" - }, - { - "x": 3, - "y": 46, - "type": "TEXT", - "value": "Chicago/Harvard", - "last_modified": "2023-02-17T00:02:04.815Z" - }, - { - "x": 4, - "y": 46, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:04.817Z" - }, - { - "x": 5, - "y": 46, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.819Z" - }, - { - "x": 6, - "y": 46, - "type": "TEXT", - "value": "42.40418556", - "last_modified": "2023-02-17T00:02:04.821Z" - }, - { - "x": 7, - "y": 46, - "type": "TEXT", - "value": "-88.63343222", - "last_modified": "2023-02-17T00:02:04.823Z" - }, - { - "x": 3, - "y": 47, - "type": "TEXT", - "value": "Pender", - "last_modified": "2023-02-17T00:02:04.832Z" - }, - { - "x": 4, - "y": 47, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:04.834Z" - }, - { - "x": 5, - "y": 47, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.836Z" - }, - { - "x": 6, - "y": 47, - "type": "TEXT", - "value": "42.11388722", - "last_modified": "2023-02-17T00:02:04.838Z" - }, - { - "x": 7, - "y": 47, - "type": "TEXT", - "value": "-96.72892556", - "last_modified": "2023-02-17T00:02:04.841Z" - }, - { - "x": 3, - "y": 48, - "type": "TEXT", - "value": "South Haven", - "last_modified": "2023-02-17T00:02:04.849Z" - }, - { - "x": 4, - "y": 48, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:04.851Z" - }, - { - "x": 5, - "y": 48, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.853Z" - }, - { - "x": 6, - "y": 48, - "type": "TEXT", - "value": "42.35083333", - "last_modified": "2023-02-17T00:02:04.855Z" - }, - { - "x": 7, - "y": 48, - "type": "TEXT", - "value": "-86.25613889", - "last_modified": "2023-02-17T00:02:04.858Z" - }, - { - "x": 3, - "y": 49, - "type": "TEXT", - "value": "Gettysburg", - "last_modified": "2023-02-17T00:02:04.866Z" - }, - { - "x": 4, - "y": 49, - "type": "TEXT", - "value": "SD", - "last_modified": "2023-02-17T00:02:04.868Z" - }, - { - "x": 5, - "y": 49, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.870Z" - }, - { - "x": 6, - "y": 49, - "type": "TEXT", - "value": "44.98730556", - "last_modified": "2023-02-17T00:02:04.872Z" - }, - { - "x": 7, - "y": 49, - "type": "TEXT", - "value": "-99.9535", - "last_modified": "2023-02-17T00:02:04.875Z" - }, - { - "x": 3, - "y": 50, - "type": "TEXT", - "value": "Moriarty", - "last_modified": "2023-02-17T00:02:04.883Z" - }, - { - "x": 4, - "y": 50, - "type": "TEXT", - "value": "NM", - "last_modified": "2023-02-17T00:02:04.885Z" - }, - { - "x": 5, - "y": 50, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.887Z" - }, - { - "x": 6, - "y": 50, - "type": "TEXT", - "value": "34.98560639", - "last_modified": "2023-02-17T00:02:04.889Z" - }, - { - "x": 7, - "y": 50, - "type": "TEXT", - "value": "-106.0094661", - "last_modified": "2023-02-17T00:02:04.892Z" - }, - { - "x": 3, - "y": 51, - "type": "TEXT", - "value": "Crownpoint", - "last_modified": "2023-02-17T00:02:04.901Z" - }, - { - "x": 4, - "y": 51, - "type": "TEXT", - "value": "NM", - "last_modified": "2023-02-17T00:02:04.903Z" - }, - { - "x": 5, - "y": 51, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.905Z" - }, - { - "x": 6, - "y": 51, - "type": "TEXT", - "value": "35.71765889", - "last_modified": "2023-02-17T00:02:04.907Z" - }, - { - "x": 7, - "y": 51, - "type": "TEXT", - "value": "-108.2015961", - "last_modified": "2023-02-17T00:02:04.909Z" - }, - { - "x": 3, - "y": 52, - "type": "TEXT", - "value": "Bowie", - "last_modified": "2023-02-17T00:02:04.917Z" - }, - { - "x": 4, - "y": 52, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:04.919Z" - }, - { - "x": 5, - "y": 52, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.922Z" - }, - { - "x": 6, - "y": 52, - "type": "TEXT", - "value": "33.60166667", - "last_modified": "2023-02-17T00:02:04.924Z" - }, - { - "x": 7, - "y": 52, - "type": "TEXT", - "value": "-97.77556", - "last_modified": "2023-02-17T00:02:04.926Z" - }, - { - "x": 3, - "y": 53, - "type": "TEXT", - "value": "Loup City", - "last_modified": "2023-02-17T00:02:04.934Z" - }, - { - "x": 4, - "y": 53, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:04.936Z" - }, - { - "x": 5, - "y": 53, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.938Z" - }, - { - "x": 6, - "y": 53, - "type": "TEXT", - "value": "41.29028694", - "last_modified": "2023-02-17T00:02:04.940Z" - }, - { - "x": 7, - "y": 53, - "type": "TEXT", - "value": "-98.99064278", - "last_modified": "2023-02-17T00:02:04.942Z" - }, - { - "x": 3, - "y": 54, - "type": "TEXT", - "value": "Eufaula", - "last_modified": "2023-02-17T00:02:04.950Z" - }, - { - "x": 4, - "y": 54, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:04.952Z" - }, - { - "x": 5, - "y": 54, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.954Z" - }, - { - "x": 6, - "y": 54, - "type": "TEXT", - "value": "35.38898833", - "last_modified": "2023-02-17T00:02:04.956Z" - }, - { - "x": 7, - "y": 54, - "type": "TEXT", - "value": "-95.60165111", - "last_modified": "2023-02-17T00:02:04.959Z" - }, - { - "x": 3, - "y": 55, - "type": "TEXT", - "value": "Sand Springs", - "last_modified": "2023-02-17T00:02:04.967Z" - }, - { - "x": 4, - "y": 55, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:04.969Z" - }, - { - "x": 5, - "y": 55, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.971Z" - }, - { - "x": 6, - "y": 55, - "type": "TEXT", - "value": "36.17528", - "last_modified": "2023-02-17T00:02:04.973Z" - }, - { - "x": 7, - "y": 55, - "type": "TEXT", - "value": "-96.15181028", - "last_modified": "2023-02-17T00:02:04.975Z" - }, - { - "x": 3, - "y": 56, - "type": "TEXT", - "value": "Tishomingo", - "last_modified": "2023-02-17T00:02:04.983Z" - }, - { - "x": 4, - "y": 56, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:04.985Z" - }, - { - "x": 5, - "y": 56, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:04.987Z" - }, - { - "x": 6, - "y": 56, - "type": "TEXT", - "value": "34.19592833", - "last_modified": "2023-02-17T00:02:04.989Z" - }, - { - "x": 7, - "y": 56, - "type": "TEXT", - "value": "-96.67555694", - "last_modified": "2023-02-17T00:02:04.991Z" - }, - { - "x": 3, - "y": 57, - "type": "TEXT", - "value": "Lockport", - "last_modified": "2023-02-17T00:02:04.999Z" - }, - { - "x": 4, - "y": 57, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:05.001Z" - }, - { - "x": 5, - "y": 57, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.003Z" - }, - { - "x": 6, - "y": 57, - "type": "TEXT", - "value": "43.10318389", - "last_modified": "2023-02-17T00:02:05.005Z" - }, - { - "x": 7, - "y": 57, - "type": "TEXT", - "value": "-78.70334583", - "last_modified": "2023-02-17T00:02:05.007Z" - }, - { - "x": 3, - "y": 58, - "type": "TEXT", - "value": "Tecumseh", - "last_modified": "2023-02-17T00:02:05.015Z" - }, - { - "x": 4, - "y": 58, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:05.017Z" - }, - { - "x": 5, - "y": 58, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.019Z" - }, - { - "x": 6, - "y": 58, - "type": "TEXT", - "value": "40.39944417", - "last_modified": "2023-02-17T00:02:05.021Z" - }, - { - "x": 7, - "y": 58, - "type": "TEXT", - "value": "-96.17139694", - "last_modified": "2023-02-17T00:02:05.023Z" - }, - { - "x": 3, - "y": 59, - "type": "TEXT", - "value": "Bryan", - "last_modified": "2023-02-17T00:02:05.031Z" - }, - { - "x": 4, - "y": 59, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:05.033Z" - }, - { - "x": 5, - "y": 59, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.035Z" - }, - { - "x": 6, - "y": 59, - "type": "TEXT", - "value": "41.46736111", - "last_modified": "2023-02-17T00:02:05.037Z" - }, - { - "x": 7, - "y": 59, - "type": "TEXT", - "value": "-84.50655556", - "last_modified": "2023-02-17T00:02:05.039Z" - }, - { - "x": 3, - "y": 60, - "type": "TEXT", - "value": "Seneca Falls", - "last_modified": "2023-02-17T00:02:05.047Z" - }, - { - "x": 4, - "y": 60, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:05.049Z" - }, - { - "x": 5, - "y": 60, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.051Z" - }, - { - "x": 6, - "y": 60, - "type": "TEXT", - "value": "42.88062278", - "last_modified": "2023-02-17T00:02:05.053Z" - }, - { - "x": 7, - "y": 60, - "type": "TEXT", - "value": "-76.78162028", - "last_modified": "2023-02-17T00:02:05.055Z" - }, - { - "x": 3, - "y": 61, - "type": "TEXT", - "value": "Wakeeney", - "last_modified": "2023-02-17T00:02:05.063Z" - }, - { - "x": 4, - "y": 61, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:05.065Z" - }, - { - "x": 5, - "y": 61, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.067Z" - }, - { - "x": 6, - "y": 61, - "type": "TEXT", - "value": "39.0044525", - "last_modified": "2023-02-17T00:02:05.069Z" - }, - { - "x": 7, - "y": 61, - "type": "TEXT", - "value": "-99.89289917", - "last_modified": "2023-02-17T00:02:05.071Z" - }, - { - "x": 3, - "y": 62, - "type": "TEXT", - "value": "Cynthiana", - "last_modified": "2023-02-17T00:02:05.079Z" - }, - { - "x": 4, - "y": 62, - "type": "TEXT", - "value": "KY", - "last_modified": "2023-02-17T00:02:05.081Z" - }, - { - "x": 5, - "y": 62, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.082Z" - }, - { - "x": 6, - "y": 62, - "type": "TEXT", - "value": "38.36674167", - "last_modified": "2023-02-17T00:02:05.084Z" - }, - { - "x": 7, - "y": 62, - "type": "TEXT", - "value": "-84.28410056", - "last_modified": "2023-02-17T00:02:05.086Z" - }, - { - "x": 3, - "y": 63, - "type": "TEXT", - "value": "Abbeville", - "last_modified": "2023-02-17T00:02:05.094Z" - }, - { - "x": 4, - "y": 63, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:05.096Z" - }, - { - "x": 5, - "y": 63, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.098Z" - }, - { - "x": 6, - "y": 63, - "type": "TEXT", - "value": "31.60016778", - "last_modified": "2023-02-17T00:02:05.100Z" - }, - { - "x": 7, - "y": 63, - "type": "TEXT", - "value": "-85.23882222", - "last_modified": "2023-02-17T00:02:05.102Z" - }, - { - "x": 3, - "y": 64, - "type": "TEXT", - "value": "Florala", - "last_modified": "2023-02-17T00:02:05.110Z" - }, - { - "x": 4, - "y": 64, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:05.112Z" - }, - { - "x": 5, - "y": 64, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.113Z" - }, - { - "x": 6, - "y": 64, - "type": "TEXT", - "value": "31.04247361", - "last_modified": "2023-02-17T00:02:05.115Z" - }, - { - "x": 7, - "y": 64, - "type": "TEXT", - "value": "-86.31156111", - "last_modified": "2023-02-17T00:02:05.117Z" - }, - { - "x": 3, - "y": 65, - "type": "TEXT", - "value": "Headland", - "last_modified": "2023-02-17T00:02:05.125Z" - }, - { - "x": 4, - "y": 65, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:05.127Z" - }, - { - "x": 5, - "y": 65, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.129Z" - }, - { - "x": 6, - "y": 65, - "type": "TEXT", - "value": "31.364895", - "last_modified": "2023-02-17T00:02:05.131Z" - }, - { - "x": 7, - "y": 65, - "type": "TEXT", - "value": "-85.30965556", - "last_modified": "2023-02-17T00:02:05.133Z" - }, - { - "x": 3, - "y": 66, - "type": "TEXT", - "value": "Humboldt", - "last_modified": "2023-02-17T00:02:05.140Z" - }, - { - "x": 4, - "y": 66, - "type": "TEXT", - "value": "IA", - "last_modified": "2023-02-17T00:02:05.142Z" - }, - { - "x": 5, - "y": 66, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.144Z" - }, - { - "x": 6, - "y": 66, - "type": "TEXT", - "value": "42.7360825", - "last_modified": "2023-02-17T00:02:05.146Z" - }, - { - "x": 7, - "y": 66, - "type": "TEXT", - "value": "-94.24524167", - "last_modified": "2023-02-17T00:02:05.148Z" - }, - { - "x": 3, - "y": 67, - "type": "TEXT", - "value": "Goldfield", - "last_modified": "2023-02-17T00:02:05.155Z" - }, - { - "x": 4, - "y": 67, - "type": "TEXT", - "value": "NV", - "last_modified": "2023-02-17T00:02:05.157Z" - }, - { - "x": 5, - "y": 67, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.159Z" - }, - { - "x": 6, - "y": 67, - "type": "TEXT", - "value": "37.71798833", - "last_modified": "2023-02-17T00:02:05.161Z" - }, - { - "x": 7, - "y": 67, - "type": "TEXT", - "value": "-117.2384119", - "last_modified": "2023-02-17T00:02:05.163Z" - }, - { - "x": 3, - "y": 68, - "type": "TEXT", - "value": "Jean", - "last_modified": "2023-02-17T00:02:05.170Z" - }, - { - "x": 4, - "y": 68, - "type": "TEXT", - "value": "NV", - "last_modified": "2023-02-17T00:02:05.172Z" - }, - { - "x": 5, - "y": 68, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.174Z" - }, - { - "x": 6, - "y": 68, - "type": "TEXT", - "value": "35.76827222", - "last_modified": "2023-02-17T00:02:05.176Z" - }, - { - "x": 7, - "y": 68, - "type": "TEXT", - "value": "-115.3296378", - "last_modified": "2023-02-17T00:02:05.178Z" - }, - { - "x": 3, - "y": 69, - "type": "TEXT", - "value": "Overton", - "last_modified": "2023-02-17T00:02:05.186Z" - }, - { - "x": 4, - "y": 69, - "type": "TEXT", - "value": "NV", - "last_modified": "2023-02-17T00:02:05.187Z" - }, - { - "x": 5, - "y": 69, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.189Z" - }, - { - "x": 6, - "y": 69, - "type": "TEXT", - "value": "36.31108972", - "last_modified": "2023-02-17T00:02:05.191Z" - }, - { - "x": 7, - "y": 69, - "type": "TEXT", - "value": "-114.4638672", - "last_modified": "2023-02-17T00:02:05.193Z" - }, - { - "x": 3, - "y": 70, - "type": "TEXT", - "value": "Dumas", - "last_modified": "2023-02-17T00:02:05.200Z" - }, - { - "x": 4, - "y": 70, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:05.202Z" - }, - { - "x": 5, - "y": 70, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.204Z" - }, - { - "x": 6, - "y": 70, - "type": "TEXT", - "value": "33.8845475", - "last_modified": "2023-02-17T00:02:05.206Z" - }, - { - "x": 7, - "y": 70, - "type": "TEXT", - "value": "-91.53429111", - "last_modified": "2023-02-17T00:02:05.208Z" - }, - { - "x": 3, - "y": 71, - "type": "TEXT", - "value": "Parsons", - "last_modified": "2023-02-17T00:02:05.215Z" - }, - { - "x": 4, - "y": 71, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:05.217Z" - }, - { - "x": 5, - "y": 71, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.219Z" - }, - { - "x": 6, - "y": 71, - "type": "TEXT", - "value": "35.63778", - "last_modified": "2023-02-17T00:02:05.221Z" - }, - { - "x": 7, - "y": 71, - "type": "TEXT", - "value": "-88.127995", - "last_modified": "2023-02-17T00:02:05.223Z" - }, - { - "x": 3, - "y": 72, - "type": "TEXT", - "value": "Camden", - "last_modified": "2023-02-17T00:02:05.230Z" - }, - { - "x": 4, - "y": 72, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:05.232Z" - }, - { - "x": 5, - "y": 72, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.234Z" - }, - { - "x": 6, - "y": 72, - "type": "TEXT", - "value": "36.01122694", - "last_modified": "2023-02-17T00:02:05.235Z" - }, - { - "x": 7, - "y": 72, - "type": "TEXT", - "value": "-88.12328833", - "last_modified": "2023-02-17T00:02:05.237Z" - }, - { - "x": 3, - "y": 73, - "type": "TEXT", - "value": "Waverly", - "last_modified": "2023-02-17T00:02:05.244Z" - }, - { - "x": 4, - "y": 73, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:05.246Z" - }, - { - "x": 5, - "y": 73, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.248Z" - }, - { - "x": 6, - "y": 73, - "type": "TEXT", - "value": "36.11659972", - "last_modified": "2023-02-17T00:02:05.250Z" - }, - { - "x": 7, - "y": 73, - "type": "TEXT", - "value": "-87.73815889", - "last_modified": "2023-02-17T00:02:05.252Z" - }, - { - "x": 3, - "y": 74, - "type": "TEXT", - "value": "Batesville", - "last_modified": "2023-02-17T00:02:05.259Z" - }, - { - "x": 4, - "y": 74, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:05.261Z" - }, - { - "x": 5, - "y": 74, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.263Z" - }, - { - "x": 6, - "y": 74, - "type": "TEXT", - "value": "34.36677444", - "last_modified": "2023-02-17T00:02:05.264Z" - }, - { - "x": 7, - "y": 74, - "type": "TEXT", - "value": "-89.90008917", - "last_modified": "2023-02-17T00:02:05.266Z" - }, - { - "x": 3, - "y": 75, - "type": "TEXT", - "value": "Lake Providence", - "last_modified": "2023-02-17T00:02:05.273Z" - }, - { - "x": 4, - "y": 75, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:05.275Z" - }, - { - "x": 5, - "y": 75, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.277Z" - }, - { - "x": 6, - "y": 75, - "type": "TEXT", - "value": "32.82587917", - "last_modified": "2023-02-17T00:02:05.279Z" - }, - { - "x": 7, - "y": 75, - "type": "TEXT", - "value": "-91.187665", - "last_modified": "2023-02-17T00:02:05.281Z" - }, - { - "x": 3, - "y": 76, - "type": "TEXT", - "value": "San Andreas", - "last_modified": "2023-02-17T00:02:05.288Z" - }, - { - "x": 4, - "y": 76, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:05.289Z" - }, - { - "x": 5, - "y": 76, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.291Z" - }, - { - "x": 6, - "y": 76, - "type": "TEXT", - "value": "38.14611639", - "last_modified": "2023-02-17T00:02:05.293Z" - }, - { - "x": 7, - "y": 76, - "type": "TEXT", - "value": "-120.6481733", - "last_modified": "2023-02-17T00:02:05.295Z" - }, - { - "x": 3, - "y": 77, - "type": "TEXT", - "value": "Corning", - "last_modified": "2023-02-17T00:02:05.302Z" - }, - { - "x": 4, - "y": 77, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:05.304Z" - }, - { - "x": 5, - "y": 77, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.305Z" - }, - { - "x": 6, - "y": 77, - "type": "TEXT", - "value": "39.94376806", - "last_modified": "2023-02-17T00:02:05.307Z" - }, - { - "x": 7, - "y": 77, - "type": "TEXT", - "value": "-122.1713781", - "last_modified": "2023-02-17T00:02:05.309Z" - }, - { - "x": 3, - "y": 78, - "type": "TEXT", - "value": "Davis", - "last_modified": "2023-02-17T00:02:05.316Z" - }, - { - "x": 4, - "y": 78, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:05.318Z" - }, - { - "x": 5, - "y": 78, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.319Z" - }, - { - "x": 6, - "y": 78, - "type": "TEXT", - "value": "38.53146222", - "last_modified": "2023-02-17T00:02:05.321Z" - }, - { - "x": 7, - "y": 78, - "type": "TEXT", - "value": "-121.7864906", - "last_modified": "2023-02-17T00:02:05.323Z" - }, - { - "x": 3, - "y": 79, - "type": "TEXT", - "value": "Shelter Cove", - "last_modified": "2023-02-17T00:02:05.330Z" - }, - { - "x": 4, - "y": 79, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:05.332Z" - }, - { - "x": 5, - "y": 79, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.334Z" - }, - { - "x": 6, - "y": 79, - "type": "TEXT", - "value": "40.02764333", - "last_modified": "2023-02-17T00:02:05.335Z" - }, - { - "x": 7, - "y": 79, - "type": "TEXT", - "value": "-124.0733639", - "last_modified": "2023-02-17T00:02:05.337Z" - }, - { - "x": 3, - "y": 80, - "type": "TEXT", - "value": "Shingletown", - "last_modified": "2023-02-17T00:02:05.344Z" - }, - { - "x": 4, - "y": 80, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:05.346Z" - }, - { - "x": 5, - "y": 80, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.348Z" - }, - { - "x": 6, - "y": 80, - "type": "TEXT", - "value": "40.52210111", - "last_modified": "2023-02-17T00:02:05.349Z" - }, - { - "x": 7, - "y": 80, - "type": "TEXT", - "value": "-121.8177683", - "last_modified": "2023-02-17T00:02:05.351Z" - }, - { - "x": 3, - "y": 81, - "type": "TEXT", - "value": "Columbia", - "last_modified": "2023-02-17T00:02:05.358Z" - }, - { - "x": 4, - "y": 81, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:05.360Z" - }, - { - "x": 5, - "y": 81, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.361Z" - }, - { - "x": 6, - "y": 81, - "type": "TEXT", - "value": "31.29700806", - "last_modified": "2023-02-17T00:02:05.363Z" - }, - { - "x": 7, - "y": 81, - "type": "TEXT", - "value": "-89.81282944", - "last_modified": "2023-02-17T00:02:05.365Z" - }, - { - "x": 3, - "y": 82, - "type": "TEXT", - "value": "Atmore", - "last_modified": "2023-02-17T00:02:05.372Z" - }, - { - "x": 4, - "y": 82, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:05.374Z" - }, - { - "x": 5, - "y": 82, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.375Z" - }, - { - "x": 6, - "y": 82, - "type": "TEXT", - "value": "31.01621528", - "last_modified": "2023-02-17T00:02:05.377Z" - }, - { - "x": 7, - "y": 82, - "type": "TEXT", - "value": "-87.44675972", - "last_modified": "2023-02-17T00:02:05.379Z" - }, - { - "x": 3, - "y": 83, - "type": "TEXT", - "value": "Abbeville", - "last_modified": "2023-02-17T00:02:05.386Z" - }, - { - "x": 4, - "y": 83, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:05.387Z" - }, - { - "x": 5, - "y": 83, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.389Z" - }, - { - "x": 6, - "y": 83, - "type": "TEXT", - "value": "29.97576083", - "last_modified": "2023-02-17T00:02:05.391Z" - }, - { - "x": 7, - "y": 83, - "type": "TEXT", - "value": "-92.08415167", - "last_modified": "2023-02-17T00:02:05.393Z" - }, - { - "x": 3, - "y": 84, - "type": "TEXT", - "value": "Vidalia", - "last_modified": "2023-02-17T00:02:05.399Z" - }, - { - "x": 4, - "y": 84, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:05.401Z" - }, - { - "x": 5, - "y": 84, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.403Z" - }, - { - "x": 6, - "y": 84, - "type": "TEXT", - "value": "31.56683278", - "last_modified": "2023-02-17T00:02:05.405Z" - }, - { - "x": 7, - "y": 84, - "type": "TEXT", - "value": "-91.50011889", - "last_modified": "2023-02-17T00:02:05.406Z" - }, - { - "x": 3, - "y": 85, - "type": "TEXT", - "value": "Winnfield", - "last_modified": "2023-02-17T00:02:05.413Z" - }, - { - "x": 4, - "y": 85, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:05.415Z" - }, - { - "x": 5, - "y": 85, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.417Z" - }, - { - "x": 6, - "y": 85, - "type": "TEXT", - "value": "31.96366222", - "last_modified": "2023-02-17T00:02:05.418Z" - }, - { - "x": 7, - "y": 85, - "type": "TEXT", - "value": "-92.66026056", - "last_modified": "2023-02-17T00:02:05.420Z" - }, - { - "x": 3, - "y": 86, - "type": "TEXT", - "value": "Coushatta", - "last_modified": "2023-02-17T00:02:05.427Z" - }, - { - "x": 4, - "y": 86, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:05.428Z" - }, - { - "x": 5, - "y": 86, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.430Z" - }, - { - "x": 6, - "y": 86, - "type": "TEXT", - "value": "31.99071694", - "last_modified": "2023-02-17T00:02:05.432Z" - }, - { - "x": 7, - "y": 86, - "type": "TEXT", - "value": "-93.30739306", - "last_modified": "2023-02-17T00:02:05.433Z" - }, - { - "x": 3, - "y": 87, - "type": "TEXT", - "value": "Oroville", - "last_modified": "2023-02-17T00:02:05.440Z" - }, - { - "x": 4, - "y": 87, - "type": "TEXT", - "value": "WA", - "last_modified": "2023-02-17T00:02:05.442Z" - }, - { - "x": 5, - "y": 87, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.443Z" - }, - { - "x": 6, - "y": 87, - "type": "TEXT", - "value": "48.958965", - "last_modified": "2023-02-17T00:02:05.445Z" - }, - { - "x": 7, - "y": 87, - "type": "TEXT", - "value": "-119.4119622", - "last_modified": "2023-02-17T00:02:05.447Z" - }, - { - "x": 3, - "y": 88, - "type": "TEXT", - "value": "Port Townsend", - "last_modified": "2023-02-17T00:02:05.453Z" - }, - { - "x": 4, - "y": 88, - "type": "TEXT", - "value": "WA", - "last_modified": "2023-02-17T00:02:05.455Z" - }, - { - "x": 5, - "y": 88, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.457Z" - }, - { - "x": 6, - "y": 88, - "type": "TEXT", - "value": "48.04981361", - "last_modified": "2023-02-17T00:02:05.458Z" - }, - { - "x": 7, - "y": 88, - "type": "TEXT", - "value": "-122.8012792", - "last_modified": "2023-02-17T00:02:05.460Z" - }, - { - "x": 3, - "y": 89, - "type": "TEXT", - "value": "Salida", - "last_modified": "2023-02-17T00:02:05.467Z" - }, - { - "x": 4, - "y": 89, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:05.468Z" - }, - { - "x": 5, - "y": 89, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.470Z" - }, - { - "x": 6, - "y": 89, - "type": "TEXT", - "value": "38.53916389", - "last_modified": "2023-02-17T00:02:05.472Z" - }, - { - "x": 7, - "y": 89, - "type": "TEXT", - "value": "-106.0458483", - "last_modified": "2023-02-17T00:02:05.473Z" - }, - { - "x": 3, - "y": 90, - "type": "TEXT", - "value": "Minden", - "last_modified": "2023-02-17T00:02:05.480Z" - }, - { - "x": 4, - "y": 90, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:05.481Z" - }, - { - "x": 5, - "y": 90, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.483Z" - }, - { - "x": 6, - "y": 90, - "type": "TEXT", - "value": "40.5149125", - "last_modified": "2023-02-17T00:02:05.485Z" - }, - { - "x": 7, - "y": 90, - "type": "TEXT", - "value": "-98.94565083", - "last_modified": "2023-02-17T00:02:05.486Z" - }, - { - "x": 3, - "y": 91, - "type": "TEXT", - "value": "Brookneal", - "last_modified": "2023-02-17T00:02:05.493Z" - }, - { - "x": 4, - "y": 91, - "type": "TEXT", - "value": "VA", - "last_modified": "2023-02-17T00:02:05.495Z" - }, - { - "x": 5, - "y": 91, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.496Z" - }, - { - "x": 6, - "y": 91, - "type": "TEXT", - "value": "37.14172222", - "last_modified": "2023-02-17T00:02:05.498Z" - }, - { - "x": 7, - "y": 91, - "type": "TEXT", - "value": "-79.01638889", - "last_modified": "2023-02-17T00:02:05.499Z" - }, - { - "x": 3, - "y": 92, - "type": "TEXT", - "value": "Mission", - "last_modified": "2023-02-17T00:02:05.506Z" - }, - { - "x": 4, - "y": 92, - "type": "TEXT", - "value": "SD", - "last_modified": "2023-02-17T00:02:05.508Z" - }, - { - "x": 5, - "y": 92, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.509Z" - }, - { - "x": 6, - "y": 92, - "type": "TEXT", - "value": "43.30694778", - "last_modified": "2023-02-17T00:02:05.511Z" - }, - { - "x": 7, - "y": 92, - "type": "TEXT", - "value": "-100.6281936", - "last_modified": "2023-02-17T00:02:05.513Z" - }, - { - "x": 3, - "y": 93, - "type": "TEXT", - "value": "Kayenta", - "last_modified": "2023-02-17T00:02:05.519Z" - }, - { - "x": 4, - "y": 93, - "type": "TEXT", - "value": "AZ", - "last_modified": "2023-02-17T00:02:05.521Z" - }, - { - "x": 5, - "y": 93, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.522Z" - }, - { - "x": 6, - "y": 93, - "type": "TEXT", - "value": "36.70972139", - "last_modified": "2023-02-17T00:02:05.524Z" - }, - { - "x": 7, - "y": 93, - "type": "TEXT", - "value": "-110.2367978", - "last_modified": "2023-02-17T00:02:05.526Z" - }, - { - "x": 3, - "y": 94, - "type": "TEXT", - "value": "Chicago/Greenwood/Wonderlake", - "last_modified": "2023-02-17T00:02:05.532Z" - }, - { - "x": 4, - "y": 94, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:05.534Z" - }, - { - "x": 5, - "y": 94, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.535Z" - }, - { - "x": 6, - "y": 94, - "type": "TEXT", - "value": "42.40266472", - "last_modified": "2023-02-17T00:02:05.537Z" - }, - { - "x": 7, - "y": 94, - "type": "TEXT", - "value": "-88.37588917", - "last_modified": "2023-02-17T00:02:05.538Z" - }, - { - "x": 3, - "y": 95, - "type": "TEXT", - "value": "Winsted", - "last_modified": "2023-02-17T00:02:05.545Z" - }, - { - "x": 4, - "y": 95, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:05.546Z" - }, - { - "x": 5, - "y": 95, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.548Z" - }, - { - "x": 6, - "y": 95, - "type": "TEXT", - "value": "44.94996278", - "last_modified": "2023-02-17T00:02:05.550Z" - }, - { - "x": 7, - "y": 95, - "type": "TEXT", - "value": "-94.0669175", - "last_modified": "2023-02-17T00:02:05.551Z" - }, - { - "x": 3, - "y": 96, - "type": "TEXT", - "value": "Millersburg", - "last_modified": "2023-02-17T00:02:05.558Z" - }, - { - "x": 4, - "y": 96, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:05.559Z" - }, - { - "x": 5, - "y": 96, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.561Z" - }, - { - "x": 6, - "y": 96, - "type": "TEXT", - "value": "40.53716667", - "last_modified": "2023-02-17T00:02:05.562Z" - }, - { - "x": 7, - "y": 96, - "type": "TEXT", - "value": "-81.95436111", - "last_modified": "2023-02-17T00:02:05.564Z" - }, - { - "x": 3, - "y": 97, - "type": "TEXT", - "value": "Wallkill", - "last_modified": "2023-02-17T00:02:05.570Z" - }, - { - "x": 4, - "y": 97, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:05.572Z" - }, - { - "x": 5, - "y": 97, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.573Z" - }, - { - "x": 6, - "y": 97, - "type": "TEXT", - "value": "41.62787111", - "last_modified": "2023-02-17T00:02:05.575Z" - }, - { - "x": 7, - "y": 97, - "type": "TEXT", - "value": "-74.13375583", - "last_modified": "2023-02-17T00:02:05.577Z" - }, - { - "x": 3, - "y": 98, - "type": "TEXT", - "value": "Owyhee", - "last_modified": "2023-02-17T00:02:05.583Z" - }, - { - "x": 4, - "y": 98, - "type": "TEXT", - "value": "NV", - "last_modified": "2023-02-17T00:02:05.584Z" - }, - { - "x": 5, - "y": 98, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.586Z" - }, - { - "x": 6, - "y": 98, - "type": "TEXT", - "value": "41.95323306", - "last_modified": "2023-02-17T00:02:05.588Z" - }, - { - "x": 7, - "y": 98, - "type": "TEXT", - "value": "-116.1876014", - "last_modified": "2023-02-17T00:02:05.589Z" - }, - { - "x": 3, - "y": 99, - "type": "TEXT", - "value": "Clayton", - "last_modified": "2023-02-17T00:02:05.595Z" - }, - { - "x": 4, - "y": 99, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:05.597Z" - }, - { - "x": 5, - "y": 99, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.599Z" - }, - { - "x": 6, - "y": 99, - "type": "TEXT", - "value": "31.88329917", - "last_modified": "2023-02-17T00:02:05.600Z" - }, - { - "x": 7, - "y": 99, - "type": "TEXT", - "value": "-85.48491361", - "last_modified": "2023-02-17T00:02:05.602Z" - }, - { - "x": 3, - "y": 100, - "type": "TEXT", - "value": "Clarion", - "last_modified": "2023-02-17T00:02:05.608Z" - }, - { - "x": 4, - "y": 100, - "type": "TEXT", - "value": "PA", - "last_modified": "2023-02-17T00:02:05.610Z" - }, - { - "x": 5, - "y": 100, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.611Z" - }, - { - "x": 6, - "y": 100, - "type": "TEXT", - "value": "41.22581222", - "last_modified": "2023-02-17T00:02:05.613Z" - }, - { - "x": 7, - "y": 100, - "type": "TEXT", - "value": "-79.44098972", - "last_modified": "2023-02-17T00:02:05.614Z" - }, - { - "x": 3, - "y": 101, - "type": "TEXT", - "value": "Chicago/Schaumburg", - "last_modified": "2023-02-17T00:02:05.620Z" - }, - { - "x": 4, - "y": 101, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:05.622Z" - }, - { - "x": 5, - "y": 101, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.623Z" - }, - { - "x": 6, - "y": 101, - "type": "TEXT", - "value": "42.04808278", - "last_modified": "2023-02-17T00:02:05.625Z" - }, - { - "x": 7, - "y": 101, - "type": "TEXT", - "value": "-88.05257194", - "last_modified": "2023-02-17T00:02:05.627Z" - }, - { - "x": 3, - "y": 102, - "type": "TEXT", - "value": "Blakely", - "last_modified": "2023-02-17T00:02:05.633Z" - }, - { - "x": 4, - "y": 102, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:05.634Z" - }, - { - "x": 5, - "y": 102, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.636Z" - }, - { - "x": 6, - "y": 102, - "type": "TEXT", - "value": "31.39698611", - "last_modified": "2023-02-17T00:02:05.637Z" - }, - { - "x": 7, - "y": 102, - "type": "TEXT", - "value": "-84.89525694", - "last_modified": "2023-02-17T00:02:05.639Z" - }, - { - "x": 3, - "y": 103, - "type": "TEXT", - "value": "Brenham", - "last_modified": "2023-02-17T00:02:05.645Z" - }, - { - "x": 4, - "y": 103, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:05.646Z" - }, - { - "x": 5, - "y": 103, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.648Z" - }, - { - "x": 6, - "y": 103, - "type": "TEXT", - "value": "30.219", - "last_modified": "2023-02-17T00:02:05.649Z" - }, - { - "x": 7, - "y": 103, - "type": "TEXT", - "value": "-96.37427778", - "last_modified": "2023-02-17T00:02:05.651Z" - }, - { - "x": 11, - "y": 4, - "type": "TEXT", - "value": "09W", - "last_modified": "2023-02-16T23:50:50.037Z" - }, - { - "x": 10, - "y": 0, - "type": "TEXT", - "value": "Calculate the distance between two airports", - "last_modified": "2023-02-16T23:54:23.031Z" - }, - { - "x": 11, - "y": 2, - "type": "TEXT", - "value": "Code", - "last_modified": "2023-02-16T23:54:34.532Z" - }, - { - "x": 12, - "y": 2, - "type": "TEXT", - "value": "index", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 13, - "y": 2, - "type": "TEXT", - "value": "iata", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 14, - "y": 2, - "type": "TEXT", - "value": "name", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 15, - "y": 2, - "type": "TEXT", - "value": "city", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 16, - "y": 2, - "type": "TEXT", - "value": "state", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 17, - "y": 2, - "type": "TEXT", - "value": "country", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 18, - "y": 2, - "type": "TEXT", - "value": "latitude", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 19, - "y": 2, - "type": "TEXT", - "value": "longitude", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 10, - "y": 3, - "type": "TEXT", - "value": "Airport 1", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 11, - "y": 3, - "type": "TEXT", - "value": "00V", - "last_modified": "2023-02-16T23:50:49.972Z" - }, - { - "x": 12, - "y": 3, - "type": "PYTHON", - "value": "2", - "python_code": "df = getCells((0, 2), (7, 503), first_row_header=True)\ndf = df[df[\"iata\"] == c(11, 3)]\ndf = df.fillna('')\ndf.columns = range(df.columns.size)\ndf\n", - "python_output": "", - "array_cells": [ - [12, 3], - [13, 3], - [14, 3], - [15, 3], - [16, 3], - [17, 3], - [18, 3], - [19, 3] - ], - "last_modified": "2023-02-17T00:03:23.613Z", - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": " 0 1 2 3 4 5 6 7\n2 2 00V Meadow Lake Colorado Springs CO USA 38.94574889 -104.5698933", - "cells_accessed": [ - [0, 2], - [0, 3], - [0, 4], - [0, 5], - [0, 6], - [0, 7], - [0, 8], - [0, 9], - [0, 10], - [0, 11], - [0, 12], - [0, 13], - [0, 14], - [0, 15], - [0, 16], - [0, 17], - [0, 18], - [0, 19], - [0, 20], - [0, 21], - [0, 22], - [0, 23], - [0, 24], - [0, 25], - [0, 26], - [0, 27], - [0, 28], - [0, 29], - [0, 30], - [0, 31], - [0, 32], - [0, 33], - [0, 34], - [0, 35], - [0, 36], - [0, 37], - [0, 38], - [0, 39], - [0, 40], - [0, 41], - [0, 42], - [0, 43], - [0, 44], - [0, 45], - [0, 46], - [0, 47], - [0, 48], - [0, 49], - [0, 50], - [0, 51], - [0, 52], - [0, 53], - [0, 54], - [0, 55], - [0, 56], - [0, 57], - [0, 58], - [0, 59], - [0, 60], - [0, 61], - [0, 62], - [0, 63], - [0, 64], - [0, 65], - [0, 66], - [0, 67], - [0, 68], - [0, 69], - [0, 70], - [0, 71], - [0, 72], - [0, 73], - [0, 74], - [0, 75], - [0, 76], - [0, 77], - [0, 78], - [0, 79], - [0, 80], - [0, 81], - [0, 82], - [0, 83], - [0, 84], - [0, 85], - [0, 86], - [0, 87], - [0, 88], - [0, 89], - [0, 90], - [0, 91], - [0, 92], - [0, 93], - [0, 94], - [0, 95], - [0, 96], - [0, 97], - [0, 98], - [0, 99], - [0, 100], - [0, 101], - [0, 102], - [0, 103], - [0, 104], - [0, 105], - [0, 106], - [0, 107], - [0, 108], - [0, 109], - [0, 110], - [0, 111], - [0, 112], - [0, 113], - [0, 114], - [0, 115], - [0, 116], - [0, 117], - [0, 118], - [0, 119], - [0, 120], - [0, 121], - [0, 122], - [0, 123], - [0, 124], - [0, 125], - [0, 126], - [0, 127], - [0, 128], - [0, 129], - [0, 130], - [0, 131], - [0, 132], - [0, 133], - [0, 134], - [0, 135], - [0, 136], - [0, 137], - [0, 138], - [0, 139], - [0, 140], - [0, 141], - [0, 142], - [0, 143], - [0, 144], - [0, 145], - [0, 146], - [0, 147], - [0, 148], - [0, 149], - [0, 150], - [0, 151], - [0, 152], - [0, 153], - [0, 154], - [0, 155], - [0, 156], - [0, 157], - [0, 158], - [0, 159], - [0, 160], - [0, 161], - [0, 162], - [0, 163], - [0, 164], - [0, 165], - [0, 166], - [0, 167], - [0, 168], - [0, 169], - [0, 170], - [0, 171], - [0, 172], - [0, 173], - [0, 174], - [0, 175], - [0, 176], - [0, 177], - [0, 178], - [0, 179], - [0, 180], - [0, 181], - [0, 182], - [0, 183], - [0, 184], - [0, 185], - [0, 186], - [0, 187], - [0, 188], - [0, 189], - [0, 190], - [0, 191], - [0, 192], - [0, 193], - [0, 194], - [0, 195], - [0, 196], - [0, 197], - [0, 198], - [0, 199], - [0, 200], - [0, 201], - [0, 202], - [0, 203], - [0, 204], - [0, 205], - [0, 206], - [0, 207], - [0, 208], - [0, 209], - [0, 210], - [0, 211], - [0, 212], - [0, 213], - [0, 214], - [0, 215], - [0, 216], - [0, 217], - [0, 218], - [0, 219], - [0, 220], - [0, 221], - [0, 222], - [0, 223], - [0, 224], - [0, 225], - [0, 226], - [0, 227], - [0, 228], - [0, 229], - [0, 230], - [0, 231], - [0, 232], - [0, 233], - [0, 234], - [0, 235], - [0, 236], - [0, 237], - [0, 238], - [0, 239], - [0, 240], - [0, 241], - [0, 242], - [0, 243], - [0, 244], - [0, 245], - [0, 246], - [0, 247], - [0, 248], - [0, 249], - [0, 250], - [0, 251], - [0, 252], - [0, 253], - [0, 254], - [0, 255], - [0, 256], - [0, 257], - [0, 258], - [0, 259], - [0, 260], - [0, 261], - [0, 262], - [0, 263], - [0, 264], - [0, 265], - [0, 266], - [0, 267], - [0, 268], - [0, 269], - [0, 270], - [0, 271], - [0, 272], - [0, 273], - [0, 274], - [0, 275], - [0, 276], - [0, 277], - [0, 278], - [0, 279], - [0, 280], - [0, 281], - [0, 282], - [0, 283], - [0, 284], - [0, 285], - [0, 286], - [0, 287], - [0, 288], - [0, 289], - [0, 290], - [0, 291], - [0, 292], - [0, 293], - [0, 294], - [0, 295], - [0, 296], - [0, 297], - [0, 298], - [0, 299], - [0, 300], - [0, 301], - [0, 302], - [0, 303], - [0, 304], - [0, 305], - [0, 306], - [0, 307], - [0, 308], - [0, 309], - [0, 310], - [0, 311], - [0, 312], - [0, 313], - [0, 314], - [0, 315], - [0, 316], - [0, 317], - [0, 318], - [0, 319], - [0, 320], - [0, 321], - [0, 322], - [0, 323], - [0, 324], - [0, 325], - [0, 326], - [0, 327], - [0, 328], - [0, 329], - [0, 330], - [0, 331], - [0, 332], - [0, 333], - [0, 334], - [0, 335], - [0, 336], - [0, 337], - [0, 338], - [0, 339], - [0, 340], - [0, 341], - [0, 342], - [0, 343], - [0, 344], - [0, 345], - [0, 346], - [0, 347], - [0, 348], - [0, 349], - [0, 350], - [0, 351], - [0, 352], - [0, 353], - [0, 354], - [0, 355], - [0, 356], - [0, 357], - [0, 358], - [0, 359], - [0, 360], - [0, 361], - [0, 362], - [0, 363], - [0, 364], - [0, 365], - [0, 366], - [0, 367], - [0, 368], - [0, 369], - [0, 370], - [0, 371], - [0, 372], - [0, 373], - [0, 374], - [0, 375], - [0, 376], - [0, 377], - [0, 378], - [0, 379], - [0, 380], - [0, 381], - [0, 382], - [0, 383], - [0, 384], - [0, 385], - [0, 386], - [0, 387], - [0, 388], - [0, 389], - [0, 390], - [0, 391], - [0, 392], - [0, 393], - [0, 394], - [0, 395], - [0, 396], - [0, 397], - [0, 398], - [0, 399], - [0, 400], - [0, 401], - [0, 402], - [0, 403], - [0, 404], - [0, 405], - [0, 406], - [0, 407], - [0, 408], - [0, 409], - [0, 410], - [0, 411], - [0, 412], - [0, 413], - [0, 414], - [0, 415], - [0, 416], - [0, 417], - [0, 418], - [0, 419], - [0, 420], - [0, 421], - [0, 422], - [0, 423], - [0, 424], - [0, 425], - [0, 426], - [0, 427], - [0, 428], - [0, 429], - [0, 430], - [0, 431], - [0, 432], - [0, 433], - [0, 434], - [0, 435], - [0, 436], - [0, 437], - [0, 438], - [0, 439], - [0, 440], - [0, 441], - [0, 442], - [0, 443], - [0, 444], - [0, 445], - [0, 446], - [0, 447], - [0, 448], - [0, 449], - [0, 450], - [0, 451], - [0, 452], - [0, 453], - [0, 454], - [0, 455], - [0, 456], - [0, 457], - [0, 458], - [0, 459], - [0, 460], - [0, 461], - [0, 462], - [0, 463], - [0, 464], - [0, 465], - [0, 466], - [0, 467], - [0, 468], - [0, 469], - [0, 470], - [0, 471], - [0, 472], - [0, 473], - [0, 474], - [0, 475], - [0, 476], - [0, 477], - [0, 478], - [0, 479], - [0, 480], - [0, 481], - [0, 482], - [0, 483], - [0, 484], - [0, 485], - [0, 486], - [0, 487], - [0, 488], - [0, 489], - [0, 490], - [0, 491], - [0, 492], - [0, 493], - [0, 494], - [0, 495], - [0, 496], - [0, 497], - [0, 498], - [0, 499], - [0, 500], - [0, 501], - [0, 502], - [0, 503], - [1, 2], - [1, 3], - [1, 4], - [1, 5], - [1, 6], - [1, 7], - [1, 8], - [1, 9], - [1, 10], - [1, 11], - [1, 12], - [1, 13], - [1, 14], - [1, 15], - [1, 16], - [1, 17], - [1, 18], - [1, 19], - [1, 20], - [1, 21], - [1, 22], - [1, 23], - [1, 24], - [1, 25], - [1, 26], - [1, 27], - [1, 28], - [1, 29], - [1, 30], - [1, 31], - [1, 32], - [1, 33], - [1, 34], - [1, 35], - [1, 36], - [1, 37], - [1, 38], - [1, 39], - [1, 40], - [1, 41], - [1, 42], - [1, 43], - [1, 44], - [1, 45], - [1, 46], - [1, 47], - [1, 48], - [1, 49], - [1, 50], - [1, 51], - [1, 52], - [1, 53], - [1, 54], - [1, 55], - [1, 56], - [1, 57], - [1, 58], - [1, 59], - [1, 60], - [1, 61], - [1, 62], - [1, 63], - [1, 64], - [1, 65], - [1, 66], - [1, 67], - [1, 68], - [1, 69], - [1, 70], - [1, 71], - [1, 72], - [1, 73], - [1, 74], - [1, 75], - [1, 76], - [1, 77], - [1, 78], - [1, 79], - [1, 80], - [1, 81], - [1, 82], - [1, 83], - [1, 84], - [1, 85], - [1, 86], - [1, 87], - [1, 88], - [1, 89], - [1, 90], - [1, 91], - [1, 92], - [1, 93], - [1, 94], - [1, 95], - [1, 96], - [1, 97], - [1, 98], - [1, 99], - [1, 100], - [1, 101], - [1, 102], - [1, 103], - [1, 104], - [1, 105], - [1, 106], - [1, 107], - [1, 108], - [1, 109], - [1, 110], - [1, 111], - [1, 112], - [1, 113], - [1, 114], - [1, 115], - [1, 116], - [1, 117], - [1, 118], - [1, 119], - [1, 120], - [1, 121], - [1, 122], - [1, 123], - [1, 124], - [1, 125], - [1, 126], - [1, 127], - [1, 128], - [1, 129], - [1, 130], - [1, 131], - [1, 132], - [1, 133], - [1, 134], - [1, 135], - [1, 136], - [1, 137], - [1, 138], - [1, 139], - [1, 140], - [1, 141], - [1, 142], - [1, 143], - [1, 144], - [1, 145], - [1, 146], - [1, 147], - [1, 148], - [1, 149], - [1, 150], - [1, 151], - [1, 152], - [1, 153], - [1, 154], - [1, 155], - [1, 156], - [1, 157], - [1, 158], - [1, 159], - [1, 160], - [1, 161], - [1, 162], - [1, 163], - [1, 164], - [1, 165], - [1, 166], - [1, 167], - [1, 168], - [1, 169], - [1, 170], - [1, 171], - [1, 172], - [1, 173], - [1, 174], - [1, 175], - [1, 176], - [1, 177], - [1, 178], - [1, 179], - [1, 180], - [1, 181], - [1, 182], - [1, 183], - [1, 184], - [1, 185], - [1, 186], - [1, 187], - [1, 188], - [1, 189], - [1, 190], - [1, 191], - [1, 192], - [1, 193], - [1, 194], - [1, 195], - [1, 196], - [1, 197], - [1, 198], - [1, 199], - [1, 200], - [1, 201], - [1, 202], - [1, 203], - [1, 204], - [1, 205], - [1, 206], - [1, 207], - [1, 208], - [1, 209], - [1, 210], - [1, 211], - [1, 212], - [1, 213], - [1, 214], - [1, 215], - [1, 216], - [1, 217], - [1, 218], - [1, 219], - [1, 220], - [1, 221], - [1, 222], - [1, 223], - [1, 224], - [1, 225], - [1, 226], - [1, 227], - [1, 228], - [1, 229], - [1, 230], - [1, 231], - [1, 232], - [1, 233], - [1, 234], - [1, 235], - [1, 236], - [1, 237], - [1, 238], - [1, 239], - [1, 240], - [1, 241], - [1, 242], - [1, 243], - [1, 244], - [1, 245], - [1, 246], - [1, 247], - [1, 248], - [1, 249], - [1, 250], - [1, 251], - [1, 252], - [1, 253], - [1, 254], - [1, 255], - [1, 256], - [1, 257], - [1, 258], - [1, 259], - [1, 260], - [1, 261], - [1, 262], - [1, 263], - [1, 264], - [1, 265], - [1, 266], - [1, 267], - [1, 268], - [1, 269], - [1, 270], - [1, 271], - [1, 272], - [1, 273], - [1, 274], - [1, 275], - [1, 276], - [1, 277], - [1, 278], - [1, 279], - [1, 280], - [1, 281], - [1, 282], - [1, 283], - [1, 284], - [1, 285], - [1, 286], - [1, 287], - [1, 288], - [1, 289], - [1, 290], - [1, 291], - [1, 292], - [1, 293], - [1, 294], - [1, 295], - [1, 296], - [1, 297], - [1, 298], - [1, 299], - [1, 300], - [1, 301], - [1, 302], - [1, 303], - [1, 304], - [1, 305], - [1, 306], - [1, 307], - [1, 308], - [1, 309], - [1, 310], - [1, 311], - [1, 312], - [1, 313], - [1, 314], - [1, 315], - [1, 316], - [1, 317], - [1, 318], - [1, 319], - [1, 320], - [1, 321], - [1, 322], - [1, 323], - [1, 324], - [1, 325], - [1, 326], - [1, 327], - [1, 328], - [1, 329], - [1, 330], - [1, 331], - [1, 332], - [1, 333], - [1, 334], - [1, 335], - [1, 336], - [1, 337], - [1, 338], - [1, 339], - [1, 340], - [1, 341], - [1, 342], - [1, 343], - [1, 344], - [1, 345], - [1, 346], - [1, 347], - [1, 348], - [1, 349], - [1, 350], - [1, 351], - [1, 352], - [1, 353], - [1, 354], - [1, 355], - [1, 356], - [1, 357], - [1, 358], - [1, 359], - [1, 360], - [1, 361], - [1, 362], - [1, 363], - [1, 364], - [1, 365], - [1, 366], - [1, 367], - [1, 368], - [1, 369], - [1, 370], - [1, 371], - [1, 372], - [1, 373], - [1, 374], - [1, 375], - [1, 376], - [1, 377], - [1, 378], - [1, 379], - [1, 380], - [1, 381], - [1, 382], - [1, 383], - [1, 384], - [1, 385], - [1, 386], - [1, 387], - [1, 388], - [1, 389], - [1, 390], - [1, 391], - [1, 392], - [1, 393], - [1, 394], - [1, 395], - [1, 396], - [1, 397], - [1, 398], - [1, 399], - [1, 400], - [1, 401], - [1, 402], - [1, 403], - [1, 404], - [1, 405], - [1, 406], - [1, 407], - [1, 408], - [1, 409], - [1, 410], - [1, 411], - [1, 412], - [1, 413], - [1, 414], - [1, 415], - [1, 416], - [1, 417], - [1, 418], - [1, 419], - [1, 420], - [1, 421], - [1, 422], - [1, 423], - [1, 424], - [1, 425], - [1, 426], - [1, 427], - [1, 428], - [1, 429], - [1, 430], - [1, 431], - [1, 432], - [1, 433], - [1, 434], - [1, 435], - [1, 436], - [1, 437], - [1, 438], - [1, 439], - [1, 440], - [1, 441], - [1, 442], - [1, 443], - [1, 444], - [1, 445], - [1, 446], - [1, 447], - [1, 448], - [1, 449], - [1, 450], - [1, 451], - [1, 452], - [1, 453], - [1, 454], - [1, 455], - [1, 456], - [1, 457], - [1, 458], - [1, 459], - [1, 460], - [1, 461], - [1, 462], - [1, 463], - [1, 464], - [1, 465], - [1, 466], - [1, 467], - [1, 468], - [1, 469], - [1, 470], - [1, 471], - [1, 472], - [1, 473], - [1, 474], - [1, 475], - [1, 476], - [1, 477], - [1, 478], - [1, 479], - [1, 480], - [1, 481], - [1, 482], - [1, 483], - [1, 484], - [1, 485], - [1, 486], - [1, 487], - [1, 488], - [1, 489], - [1, 490], - [1, 491], - [1, 492], - [1, 493], - [1, 494], - [1, 495], - [1, 496], - [1, 497], - [1, 498], - [1, 499], - [1, 500], - [1, 501], - [1, 502], - [1, 503], - [2, 2], - [2, 3], - [2, 4], - [2, 5], - [2, 6], - [2, 7], - [2, 8], - [2, 9], - [2, 10], - [2, 11], - [2, 12], - [2, 13], - [2, 14], - [2, 15], - [2, 16], - [2, 17], - [2, 18], - [2, 19], - [2, 20], - [2, 21], - [2, 22], - [2, 23], - [2, 24], - [2, 25], - [2, 26], - [2, 27], - [2, 28], - [2, 29], - [2, 30], - [2, 31], - [2, 32], - [2, 33], - [2, 34], - [2, 35], - [2, 36], - [2, 37], - [2, 38], - [2, 39], - [2, 40], - [2, 41], - [2, 42], - [2, 43], - [2, 44], - [2, 45], - [2, 46], - [2, 47], - [2, 48], - [2, 49], - [2, 50], - [2, 51], - [2, 52], - [2, 53], - [2, 54], - [2, 55], - [2, 56], - [2, 57], - [2, 58], - [2, 59], - [2, 60], - [2, 61], - [2, 62], - [2, 63], - [2, 64], - [2, 65], - [2, 66], - [2, 67], - [2, 68], - [2, 69], - [2, 70], - [2, 71], - [2, 72], - [2, 73], - [2, 74], - [2, 75], - [2, 76], - [2, 77], - [2, 78], - [2, 79], - [2, 80], - [2, 81], - [2, 82], - [2, 83], - [2, 84], - [2, 85], - [2, 86], - [2, 87], - [2, 88], - [2, 89], - [2, 90], - [2, 91], - [2, 92], - [2, 93], - [2, 94], - [2, 95], - [2, 96], - [2, 97], - [2, 98], - [2, 99], - [2, 100], - [2, 101], - [2, 102], - [2, 103], - [2, 104], - [2, 105], - [2, 106], - [2, 107], - [2, 108], - [2, 109], - [2, 110], - [2, 111], - [2, 112], - [2, 113], - [2, 114], - [2, 115], - [2, 116], - [2, 117], - [2, 118], - [2, 119], - [2, 120], - [2, 121], - [2, 122], - [2, 123], - [2, 124], - [2, 125], - [2, 126], - [2, 127], - [2, 128], - [2, 129], - [2, 130], - [2, 131], - [2, 132], - [2, 133], - [2, 134], - [2, 135], - [2, 136], - [2, 137], - [2, 138], - [2, 139], - [2, 140], - [2, 141], - [2, 142], - [2, 143], - [2, 144], - [2, 145], - [2, 146], - [2, 147], - [2, 148], - [2, 149], - [2, 150], - [2, 151], - [2, 152], - [2, 153], - [2, 154], - [2, 155], - [2, 156], - [2, 157], - [2, 158], - [2, 159], - [2, 160], - [2, 161], - [2, 162], - [2, 163], - [2, 164], - [2, 165], - [2, 166], - [2, 167], - [2, 168], - [2, 169], - [2, 170], - [2, 171], - [2, 172], - [2, 173], - [2, 174], - [2, 175], - [2, 176], - [2, 177], - [2, 178], - [2, 179], - [2, 180], - [2, 181], - [2, 182], - [2, 183], - [2, 184], - [2, 185], - [2, 186], - [2, 187], - [2, 188], - [2, 189], - [2, 190], - [2, 191], - [2, 192], - [2, 193], - [2, 194], - [2, 195], - [2, 196], - [2, 197], - [2, 198], - [2, 199], - [2, 200], - [2, 201], - [2, 202], - [2, 203], - [2, 204], - [2, 205], - [2, 206], - [2, 207], - [2, 208], - [2, 209], - [2, 210], - [2, 211], - [2, 212], - [2, 213], - [2, 214], - [2, 215], - [2, 216], - [2, 217], - [2, 218], - [2, 219], - [2, 220], - [2, 221], - [2, 222], - [2, 223], - [2, 224], - [2, 225], - [2, 226], - [2, 227], - [2, 228], - [2, 229], - [2, 230], - [2, 231], - [2, 232], - [2, 233], - [2, 234], - [2, 235], - [2, 236], - [2, 237], - [2, 238], - [2, 239], - [2, 240], - [2, 241], - [2, 242], - [2, 243], - [2, 244], - [2, 245], - [2, 246], - [2, 247], - [2, 248], - [2, 249], - [2, 250], - [2, 251], - [2, 252], - [2, 253], - [2, 254], - [2, 255], - [2, 256], - [2, 257], - [2, 258], - [2, 259], - [2, 260], - [2, 261], - [2, 262], - [2, 263], - [2, 264], - [2, 265], - [2, 266], - [2, 267], - [2, 268], - [2, 269], - [2, 270], - [2, 271], - [2, 272], - [2, 273], - [2, 274], - [2, 275], - [2, 276], - [2, 277], - [2, 278], - [2, 279], - [2, 280], - [2, 281], - [2, 282], - [2, 283], - [2, 284], - [2, 285], - [2, 286], - [2, 287], - [2, 288], - [2, 289], - [2, 290], - [2, 291], - [2, 292], - [2, 293], - [2, 294], - [2, 295], - [2, 296], - [2, 297], - [2, 298], - [2, 299], - [2, 300], - [2, 301], - [2, 302], - [2, 303], - [2, 304], - [2, 305], - [2, 306], - [2, 307], - [2, 308], - [2, 309], - [2, 310], - [2, 311], - [2, 312], - [2, 313], - [2, 314], - [2, 315], - [2, 316], - [2, 317], - [2, 318], - [2, 319], - [2, 320], - [2, 321], - [2, 322], - [2, 323], - [2, 324], - [2, 325], - [2, 326], - [2, 327], - [2, 328], - [2, 329], - [2, 330], - [2, 331], - [2, 332], - [2, 333], - [2, 334], - [2, 335], - [2, 336], - [2, 337], - [2, 338], - [2, 339], - [2, 340], - [2, 341], - [2, 342], - [2, 343], - [2, 344], - [2, 345], - [2, 346], - [2, 347], - [2, 348], - [2, 349], - [2, 350], - [2, 351], - [2, 352], - [2, 353], - [2, 354], - [2, 355], - [2, 356], - [2, 357], - [2, 358], - [2, 359], - [2, 360], - [2, 361], - [2, 362], - [2, 363], - [2, 364], - [2, 365], - [2, 366], - [2, 367], - [2, 368], - [2, 369], - [2, 370], - [2, 371], - [2, 372], - [2, 373], - [2, 374], - [2, 375], - [2, 376], - [2, 377], - [2, 378], - [2, 379], - [2, 380], - [2, 381], - [2, 382], - [2, 383], - [2, 384], - [2, 385], - [2, 386], - [2, 387], - [2, 388], - [2, 389], - [2, 390], - [2, 391], - [2, 392], - [2, 393], - [2, 394], - [2, 395], - [2, 396], - [2, 397], - [2, 398], - [2, 399], - [2, 400], - [2, 401], - [2, 402], - [2, 403], - [2, 404], - [2, 405], - [2, 406], - [2, 407], - [2, 408], - [2, 409], - [2, 410], - [2, 411], - [2, 412], - [2, 413], - [2, 414], - [2, 415], - [2, 416], - [2, 417], - [2, 418], - [2, 419], - [2, 420], - [2, 421], - [2, 422], - [2, 423], - [2, 424], - [2, 425], - [2, 426], - [2, 427], - [2, 428], - [2, 429], - [2, 430], - [2, 431], - [2, 432], - [2, 433], - [2, 434], - [2, 435], - [2, 436], - [2, 437], - [2, 438], - [2, 439], - [2, 440], - [2, 441], - [2, 442], - [2, 443], - [2, 444], - [2, 445], - [2, 446], - [2, 447], - [2, 448], - [2, 449], - [2, 450], - [2, 451], - [2, 452], - [2, 453], - [2, 454], - [2, 455], - [2, 456], - [2, 457], - [2, 458], - [2, 459], - [2, 460], - [2, 461], - [2, 462], - [2, 463], - [2, 464], - [2, 465], - [2, 466], - [2, 467], - [2, 468], - [2, 469], - [2, 470], - [2, 471], - [2, 472], - [2, 473], - [2, 474], - [2, 475], - [2, 476], - [2, 477], - [2, 478], - [2, 479], - [2, 480], - [2, 481], - [2, 482], - [2, 483], - [2, 484], - [2, 485], - [2, 486], - [2, 487], - [2, 488], - [2, 489], - [2, 490], - [2, 491], - [2, 492], - [2, 493], - [2, 494], - [2, 495], - [2, 496], - [2, 497], - [2, 498], - [2, 499], - [2, 500], - [2, 501], - [2, 502], - [2, 503], - [3, 2], - [3, 3], - [3, 4], - [3, 5], - [3, 6], - [3, 7], - [3, 8], - [3, 9], - [3, 10], - [3, 11], - [3, 12], - [3, 13], - [3, 14], - [3, 15], - [3, 16], - [3, 17], - [3, 18], - [3, 19], - [3, 20], - [3, 21], - [3, 22], - [3, 23], - [3, 24], - [3, 25], - [3, 26], - [3, 27], - [3, 28], - [3, 29], - [3, 30], - [3, 31], - [3, 32], - [3, 33], - [3, 34], - [3, 35], - [3, 36], - [3, 37], - [3, 38], - [3, 39], - [3, 40], - [3, 41], - [3, 42], - [3, 43], - [3, 44], - [3, 45], - [3, 46], - [3, 47], - [3, 48], - [3, 49], - [3, 50], - [3, 51], - [3, 52], - [3, 53], - [3, 54], - [3, 55], - [3, 56], - [3, 57], - [3, 58], - [3, 59], - [3, 60], - [3, 61], - [3, 62], - [3, 63], - [3, 64], - [3, 65], - [3, 66], - [3, 67], - [3, 68], - [3, 69], - [3, 70], - [3, 71], - [3, 72], - [3, 73], - [3, 74], - [3, 75], - [3, 76], - [3, 77], - [3, 78], - [3, 79], - [3, 80], - [3, 81], - [3, 82], - [3, 83], - [3, 84], - [3, 85], - [3, 86], - [3, 87], - [3, 88], - [3, 89], - [3, 90], - [3, 91], - [3, 92], - [3, 93], - [3, 94], - [3, 95], - [3, 96], - [3, 97], - [3, 98], - [3, 99], - [3, 100], - [3, 101], - [3, 102], - [3, 103], - [3, 104], - [3, 105], - [3, 106], - [3, 107], - [3, 108], - [3, 109], - [3, 110], - [3, 111], - [3, 112], - [3, 113], - [3, 114], - [3, 115], - [3, 116], - [3, 117], - [3, 118], - [3, 119], - [3, 120], - [3, 121], - [3, 122], - [3, 123], - [3, 124], - [3, 125], - [3, 126], - [3, 127], - [3, 128], - [3, 129], - [3, 130], - [3, 131], - [3, 132], - [3, 133], - [3, 134], - [3, 135], - [3, 136], - [3, 137], - [3, 138], - [3, 139], - [3, 140], - [3, 141], - [3, 142], - [3, 143], - [3, 144], - [3, 145], - [3, 146], - [3, 147], - [3, 148], - [3, 149], - [3, 150], - [3, 151], - [3, 152], - [3, 153], - [3, 154], - [3, 155], - [3, 156], - [3, 157], - [3, 158], - [3, 159], - [3, 160], - [3, 161], - [3, 162], - [3, 163], - [3, 164], - [3, 165], - [3, 166], - [3, 167], - [3, 168], - [3, 169], - [3, 170], - [3, 171], - [3, 172], - [3, 173], - [3, 174], - [3, 175], - [3, 176], - [3, 177], - [3, 178], - [3, 179], - [3, 180], - [3, 181], - [3, 182], - [3, 183], - [3, 184], - [3, 185], - [3, 186], - [3, 187], - [3, 188], - [3, 189], - [3, 190], - [3, 191], - [3, 192], - [3, 193], - [3, 194], - [3, 195], - [3, 196], - [3, 197], - [3, 198], - [3, 199], - [3, 200], - [3, 201], - [3, 202], - [3, 203], - [3, 204], - [3, 205], - [3, 206], - [3, 207], - [3, 208], - [3, 209], - [3, 210], - [3, 211], - [3, 212], - [3, 213], - [3, 214], - [3, 215], - [3, 216], - [3, 217], - [3, 218], - [3, 219], - [3, 220], - [3, 221], - [3, 222], - [3, 223], - [3, 224], - [3, 225], - [3, 226], - [3, 227], - [3, 228], - [3, 229], - [3, 230], - [3, 231], - [3, 232], - [3, 233], - [3, 234], - [3, 235], - [3, 236], - [3, 237], - [3, 238], - [3, 239], - [3, 240], - [3, 241], - [3, 242], - [3, 243], - [3, 244], - [3, 245], - [3, 246], - [3, 247], - [3, 248], - [3, 249], - [3, 250], - [3, 251], - [3, 252], - [3, 253], - [3, 254], - [3, 255], - [3, 256], - [3, 257], - [3, 258], - [3, 259], - [3, 260], - [3, 261], - [3, 262], - [3, 263], - [3, 264], - [3, 265], - [3, 266], - [3, 267], - [3, 268], - [3, 269], - [3, 270], - [3, 271], - [3, 272], - [3, 273], - [3, 274], - [3, 275], - [3, 276], - [3, 277], - [3, 278], - [3, 279], - [3, 280], - [3, 281], - [3, 282], - [3, 283], - [3, 284], - [3, 285], - [3, 286], - [3, 287], - [3, 288], - [3, 289], - [3, 290], - [3, 291], - [3, 292], - [3, 293], - [3, 294], - [3, 295], - [3, 296], - [3, 297], - [3, 298], - [3, 299], - [3, 300], - [3, 301], - [3, 302], - [3, 303], - [3, 304], - [3, 305], - [3, 306], - [3, 307], - [3, 308], - [3, 309], - [3, 310], - [3, 311], - [3, 312], - [3, 313], - [3, 314], - [3, 315], - [3, 316], - [3, 317], - [3, 318], - [3, 319], - [3, 320], - [3, 321], - [3, 322], - [3, 323], - [3, 324], - [3, 325], - [3, 326], - [3, 327], - [3, 328], - [3, 329], - [3, 330], - [3, 331], - [3, 332], - [3, 333], - [3, 334], - [3, 335], - [3, 336], - [3, 337], - [3, 338], - [3, 339], - [3, 340], - [3, 341], - [3, 342], - [3, 343], - [3, 344], - [3, 345], - [3, 346], - [3, 347], - [3, 348], - [3, 349], - [3, 350], - [3, 351], - [3, 352], - [3, 353], - [3, 354], - [3, 355], - [3, 356], - [3, 357], - [3, 358], - [3, 359], - [3, 360], - [3, 361], - [3, 362], - [3, 363], - [3, 364], - [3, 365], - [3, 366], - [3, 367], - [3, 368], - [3, 369], - [3, 370], - [3, 371], - [3, 372], - [3, 373], - [3, 374], - [3, 375], - [3, 376], - [3, 377], - [3, 378], - [3, 379], - [3, 380], - [3, 381], - [3, 382], - [3, 383], - [3, 384], - [3, 385], - [3, 386], - [3, 387], - [3, 388], - [3, 389], - [3, 390], - [3, 391], - [3, 392], - [3, 393], - [3, 394], - [3, 395], - [3, 396], - [3, 397], - [3, 398], - [3, 399], - [3, 400], - [3, 401], - [3, 402], - [3, 403], - [3, 404], - [3, 405], - [3, 406], - [3, 407], - [3, 408], - [3, 409], - [3, 410], - [3, 411], - [3, 412], - [3, 413], - [3, 414], - [3, 415], - [3, 416], - [3, 417], - [3, 418], - [3, 419], - [3, 420], - [3, 421], - [3, 422], - [3, 423], - [3, 424], - [3, 425], - [3, 426], - [3, 427], - [3, 428], - [3, 429], - [3, 430], - [3, 431], - [3, 432], - [3, 433], - [3, 434], - [3, 435], - [3, 436], - [3, 437], - [3, 438], - [3, 439], - [3, 440], - [3, 441], - [3, 442], - [3, 443], - [3, 444], - [3, 445], - [3, 446], - [3, 447], - [3, 448], - [3, 449], - [3, 450], - [3, 451], - [3, 452], - [3, 453], - [3, 454], - [3, 455], - [3, 456], - [3, 457], - [3, 458], - [3, 459], - [3, 460], - [3, 461], - [3, 462], - [3, 463], - [3, 464], - [3, 465], - [3, 466], - [3, 467], - [3, 468], - [3, 469], - [3, 470], - [3, 471], - [3, 472], - [3, 473], - [3, 474], - [3, 475], - [3, 476], - [3, 477], - [3, 478], - [3, 479], - [3, 480], - [3, 481], - [3, 482], - [3, 483], - [3, 484], - [3, 485], - [3, 486], - [3, 487], - [3, 488], - [3, 489], - [3, 490], - [3, 491], - [3, 492], - [3, 493], - [3, 494], - [3, 495], - [3, 496], - [3, 497], - [3, 498], - [3, 499], - [3, 500], - [3, 501], - [3, 502], - [3, 503], - [4, 2], - [4, 3], - [4, 4], - [4, 5], - [4, 6], - [4, 7], - [4, 8], - [4, 9], - [4, 10], - [4, 11], - [4, 12], - [4, 13], - [4, 14], - [4, 15], - [4, 16], - [4, 17], - [4, 18], - [4, 19], - [4, 20], - [4, 21], - [4, 22], - [4, 23], - [4, 24], - [4, 25], - [4, 26], - [4, 27], - [4, 28], - [4, 29], - [4, 30], - [4, 31], - [4, 32], - [4, 33], - [4, 34], - [4, 35], - [4, 36], - [4, 37], - [4, 38], - [4, 39], - [4, 40], - [4, 41], - [4, 42], - [4, 43], - [4, 44], - [4, 45], - [4, 46], - [4, 47], - [4, 48], - [4, 49], - [4, 50], - [4, 51], - [4, 52], - [4, 53], - [4, 54], - [4, 55], - [4, 56], - [4, 57], - [4, 58], - [4, 59], - [4, 60], - [4, 61], - [4, 62], - [4, 63], - [4, 64], - [4, 65], - [4, 66], - [4, 67], - [4, 68], - [4, 69], - [4, 70], - [4, 71], - [4, 72], - [4, 73], - [4, 74], - [4, 75], - [4, 76], - [4, 77], - [4, 78], - [4, 79], - [4, 80], - [4, 81], - [4, 82], - [4, 83], - [4, 84], - [4, 85], - [4, 86], - [4, 87], - [4, 88], - [4, 89], - [4, 90], - [4, 91], - [4, 92], - [4, 93], - [4, 94], - [4, 95], - [4, 96], - [4, 97], - [4, 98], - [4, 99], - [4, 100], - [4, 101], - [4, 102], - [4, 103], - [4, 104], - [4, 105], - [4, 106], - [4, 107], - [4, 108], - [4, 109], - [4, 110], - [4, 111], - [4, 112], - [4, 113], - [4, 114], - [4, 115], - [4, 116], - [4, 117], - [4, 118], - [4, 119], - [4, 120], - [4, 121], - [4, 122], - [4, 123], - [4, 124], - [4, 125], - [4, 126], - [4, 127], - [4, 128], - [4, 129], - [4, 130], - [4, 131], - [4, 132], - [4, 133], - [4, 134], - [4, 135], - [4, 136], - [4, 137], - [4, 138], - [4, 139], - [4, 140], - [4, 141], - [4, 142], - [4, 143], - [4, 144], - [4, 145], - [4, 146], - [4, 147], - [4, 148], - [4, 149], - [4, 150], - [4, 151], - [4, 152], - [4, 153], - [4, 154], - [4, 155], - [4, 156], - [4, 157], - [4, 158], - [4, 159], - [4, 160], - [4, 161], - [4, 162], - [4, 163], - [4, 164], - [4, 165], - [4, 166], - [4, 167], - [4, 168], - [4, 169], - [4, 170], - [4, 171], - [4, 172], - [4, 173], - [4, 174], - [4, 175], - [4, 176], - [4, 177], - [4, 178], - [4, 179], - [4, 180], - [4, 181], - [4, 182], - [4, 183], - [4, 184], - [4, 185], - [4, 186], - [4, 187], - [4, 188], - [4, 189], - [4, 190], - [4, 191], - [4, 192], - [4, 193], - [4, 194], - [4, 195], - [4, 196], - [4, 197], - [4, 198], - [4, 199], - [4, 200], - [4, 201], - [4, 202], - [4, 203], - [4, 204], - [4, 205], - [4, 206], - [4, 207], - [4, 208], - [4, 209], - [4, 210], - [4, 211], - [4, 212], - [4, 213], - [4, 214], - [4, 215], - [4, 216], - [4, 217], - [4, 218], - [4, 219], - [4, 220], - [4, 221], - [4, 222], - [4, 223], - [4, 224], - [4, 225], - [4, 226], - [4, 227], - [4, 228], - [4, 229], - [4, 230], - [4, 231], - [4, 232], - [4, 233], - [4, 234], - [4, 235], - [4, 236], - [4, 237], - [4, 238], - [4, 239], - [4, 240], - [4, 241], - [4, 242], - [4, 243], - [4, 244], - [4, 245], - [4, 246], - [4, 247], - [4, 248], - [4, 249], - [4, 250], - [4, 251], - [4, 252], - [4, 253], - [4, 254], - [4, 255], - [4, 256], - [4, 257], - [4, 258], - [4, 259], - [4, 260], - [4, 261], - [4, 262], - [4, 263], - [4, 264], - [4, 265], - [4, 266], - [4, 267], - [4, 268], - [4, 269], - [4, 270], - [4, 271], - [4, 272], - [4, 273], - [4, 274], - [4, 275], - [4, 276], - [4, 277], - [4, 278], - [4, 279], - [4, 280], - [4, 281], - [4, 282], - [4, 283], - [4, 284], - [4, 285], - [4, 286], - [4, 287], - [4, 288], - [4, 289], - [4, 290], - [4, 291], - [4, 292], - [4, 293], - [4, 294], - [4, 295], - [4, 296], - [4, 297], - [4, 298], - [4, 299], - [4, 300], - [4, 301], - [4, 302], - [4, 303], - [4, 304], - [4, 305], - [4, 306], - [4, 307], - [4, 308], - [4, 309], - [4, 310], - [4, 311], - [4, 312], - [4, 313], - [4, 314], - [4, 315], - [4, 316], - [4, 317], - [4, 318], - [4, 319], - [4, 320], - [4, 321], - [4, 322], - [4, 323], - [4, 324], - [4, 325], - [4, 326], - [4, 327], - [4, 328], - [4, 329], - [4, 330], - [4, 331], - [4, 332], - [4, 333], - [4, 334], - [4, 335], - [4, 336], - [4, 337], - [4, 338], - [4, 339], - [4, 340], - [4, 341], - [4, 342], - [4, 343], - [4, 344], - [4, 345], - [4, 346], - [4, 347], - [4, 348], - [4, 349], - [4, 350], - [4, 351], - [4, 352], - [4, 353], - [4, 354], - [4, 355], - [4, 356], - [4, 357], - [4, 358], - [4, 359], - [4, 360], - [4, 361], - [4, 362], - [4, 363], - [4, 364], - [4, 365], - [4, 366], - [4, 367], - [4, 368], - [4, 369], - [4, 370], - [4, 371], - [4, 372], - [4, 373], - [4, 374], - [4, 375], - [4, 376], - [4, 377], - [4, 378], - [4, 379], - [4, 380], - [4, 381], - [4, 382], - [4, 383], - [4, 384], - [4, 385], - [4, 386], - [4, 387], - [4, 388], - [4, 389], - [4, 390], - [4, 391], - [4, 392], - [4, 393], - [4, 394], - [4, 395], - [4, 396], - [4, 397], - [4, 398], - [4, 399], - [4, 400], - [4, 401], - [4, 402], - [4, 403], - [4, 404], - [4, 405], - [4, 406], - [4, 407], - [4, 408], - [4, 409], - [4, 410], - [4, 411], - [4, 412], - [4, 413], - [4, 414], - [4, 415], - [4, 416], - [4, 417], - [4, 418], - [4, 419], - [4, 420], - [4, 421], - [4, 422], - [4, 423], - [4, 424], - [4, 425], - [4, 426], - [4, 427], - [4, 428], - [4, 429], - [4, 430], - [4, 431], - [4, 432], - [4, 433], - [4, 434], - [4, 435], - [4, 436], - [4, 437], - [4, 438], - [4, 439], - [4, 440], - [4, 441], - [4, 442], - [4, 443], - [4, 444], - [4, 445], - [4, 446], - [4, 447], - [4, 448], - [4, 449], - [4, 450], - [4, 451], - [4, 452], - [4, 453], - [4, 454], - [4, 455], - [4, 456], - [4, 457], - [4, 458], - [4, 459], - [4, 460], - [4, 461], - [4, 462], - [4, 463], - [4, 464], - [4, 465], - [4, 466], - [4, 467], - [4, 468], - [4, 469], - [4, 470], - [4, 471], - [4, 472], - [4, 473], - [4, 474], - [4, 475], - [4, 476], - [4, 477], - [4, 478], - [4, 479], - [4, 480], - [4, 481], - [4, 482], - [4, 483], - [4, 484], - [4, 485], - [4, 486], - [4, 487], - [4, 488], - [4, 489], - [4, 490], - [4, 491], - [4, 492], - [4, 493], - [4, 494], - [4, 495], - [4, 496], - [4, 497], - [4, 498], - [4, 499], - [4, 500], - [4, 501], - [4, 502], - [4, 503], - [5, 2], - [5, 3], - [5, 4], - [5, 5], - [5, 6], - [5, 7], - [5, 8], - [5, 9], - [5, 10], - [5, 11], - [5, 12], - [5, 13], - [5, 14], - [5, 15], - [5, 16], - [5, 17], - [5, 18], - [5, 19], - [5, 20], - [5, 21], - [5, 22], - [5, 23], - [5, 24], - [5, 25], - [5, 26], - [5, 27], - [5, 28], - [5, 29], - [5, 30], - [5, 31], - [5, 32], - [5, 33], - [5, 34], - [5, 35], - [5, 36], - [5, 37], - [5, 38], - [5, 39], - [5, 40], - [5, 41], - [5, 42], - [5, 43], - [5, 44], - [5, 45], - [5, 46], - [5, 47], - [5, 48], - [5, 49], - [5, 50], - [5, 51], - [5, 52], - [5, 53], - [5, 54], - [5, 55], - [5, 56], - [5, 57], - [5, 58], - [5, 59], - [5, 60], - [5, 61], - [5, 62], - [5, 63], - [5, 64], - [5, 65], - [5, 66], - [5, 67], - [5, 68], - [5, 69], - [5, 70], - [5, 71], - [5, 72], - [5, 73], - [5, 74], - [5, 75], - [5, 76], - [5, 77], - [5, 78], - [5, 79], - [5, 80], - [5, 81], - [5, 82], - [5, 83], - [5, 84], - [5, 85], - [5, 86], - [5, 87], - [5, 88], - [5, 89], - [5, 90], - [5, 91], - [5, 92], - [5, 93], - [5, 94], - [5, 95], - [5, 96], - [5, 97], - [5, 98], - [5, 99], - [5, 100], - [5, 101], - [5, 102], - [5, 103], - [5, 104], - [5, 105], - [5, 106], - [5, 107], - [5, 108], - [5, 109], - [5, 110], - [5, 111], - [5, 112], - [5, 113], - [5, 114], - [5, 115], - [5, 116], - [5, 117], - [5, 118], - [5, 119], - [5, 120], - [5, 121], - [5, 122], - [5, 123], - [5, 124], - [5, 125], - [5, 126], - [5, 127], - [5, 128], - [5, 129], - [5, 130], - [5, 131], - [5, 132], - [5, 133], - [5, 134], - [5, 135], - [5, 136], - [5, 137], - [5, 138], - [5, 139], - [5, 140], - [5, 141], - [5, 142], - [5, 143], - [5, 144], - [5, 145], - [5, 146], - [5, 147], - [5, 148], - [5, 149], - [5, 150], - [5, 151], - [5, 152], - [5, 153], - [5, 154], - [5, 155], - [5, 156], - [5, 157], - [5, 158], - [5, 159], - [5, 160], - [5, 161], - [5, 162], - [5, 163], - [5, 164], - [5, 165], - [5, 166], - [5, 167], - [5, 168], - [5, 169], - [5, 170], - [5, 171], - [5, 172], - [5, 173], - [5, 174], - [5, 175], - [5, 176], - [5, 177], - [5, 178], - [5, 179], - [5, 180], - [5, 181], - [5, 182], - [5, 183], - [5, 184], - [5, 185], - [5, 186], - [5, 187], - [5, 188], - [5, 189], - [5, 190], - [5, 191], - [5, 192], - [5, 193], - [5, 194], - [5, 195], - [5, 196], - [5, 197], - [5, 198], - [5, 199], - [5, 200], - [5, 201], - [5, 202], - [5, 203], - [5, 204], - [5, 205], - [5, 206], - [5, 207], - [5, 208], - [5, 209], - [5, 210], - [5, 211], - [5, 212], - [5, 213], - [5, 214], - [5, 215], - [5, 216], - [5, 217], - [5, 218], - [5, 219], - [5, 220], - [5, 221], - [5, 222], - [5, 223], - [5, 224], - [5, 225], - [5, 226], - [5, 227], - [5, 228], - [5, 229], - [5, 230], - [5, 231], - [5, 232], - [5, 233], - [5, 234], - [5, 235], - [5, 236], - [5, 237], - [5, 238], - [5, 239], - [5, 240], - [5, 241], - [5, 242], - [5, 243], - [5, 244], - [5, 245], - [5, 246], - [5, 247], - [5, 248], - [5, 249], - [5, 250], - [5, 251], - [5, 252], - [5, 253], - [5, 254], - [5, 255], - [5, 256], - [5, 257], - [5, 258], - [5, 259], - [5, 260], - [5, 261], - [5, 262], - [5, 263], - [5, 264], - [5, 265], - [5, 266], - [5, 267], - [5, 268], - [5, 269], - [5, 270], - [5, 271], - [5, 272], - [5, 273], - [5, 274], - [5, 275], - [5, 276], - [5, 277], - [5, 278], - [5, 279], - [5, 280], - [5, 281], - [5, 282], - [5, 283], - [5, 284], - [5, 285], - [5, 286], - [5, 287], - [5, 288], - [5, 289], - [5, 290], - [5, 291], - [5, 292], - [5, 293], - [5, 294], - [5, 295], - [5, 296], - [5, 297], - [5, 298], - [5, 299], - [5, 300], - [5, 301], - [5, 302], - [5, 303], - [5, 304], - [5, 305], - [5, 306], - [5, 307], - [5, 308], - [5, 309], - [5, 310], - [5, 311], - [5, 312], - [5, 313], - [5, 314], - [5, 315], - [5, 316], - [5, 317], - [5, 318], - [5, 319], - [5, 320], - [5, 321], - [5, 322], - [5, 323], - [5, 324], - [5, 325], - [5, 326], - [5, 327], - [5, 328], - [5, 329], - [5, 330], - [5, 331], - [5, 332], - [5, 333], - [5, 334], - [5, 335], - [5, 336], - [5, 337], - [5, 338], - [5, 339], - [5, 340], - [5, 341], - [5, 342], - [5, 343], - [5, 344], - [5, 345], - [5, 346], - [5, 347], - [5, 348], - [5, 349], - [5, 350], - [5, 351], - [5, 352], - [5, 353], - [5, 354], - [5, 355], - [5, 356], - [5, 357], - [5, 358], - [5, 359], - [5, 360], - [5, 361], - [5, 362], - [5, 363], - [5, 364], - [5, 365], - [5, 366], - [5, 367], - [5, 368], - [5, 369], - [5, 370], - [5, 371], - [5, 372], - [5, 373], - [5, 374], - [5, 375], - [5, 376], - [5, 377], - [5, 378], - [5, 379], - [5, 380], - [5, 381], - [5, 382], - [5, 383], - [5, 384], - [5, 385], - [5, 386], - [5, 387], - [5, 388], - [5, 389], - [5, 390], - [5, 391], - [5, 392], - [5, 393], - [5, 394], - [5, 395], - [5, 396], - [5, 397], - [5, 398], - [5, 399], - [5, 400], - [5, 401], - [5, 402], - [5, 403], - [5, 404], - [5, 405], - [5, 406], - [5, 407], - [5, 408], - [5, 409], - [5, 410], - [5, 411], - [5, 412], - [5, 413], - [5, 414], - [5, 415], - [5, 416], - [5, 417], - [5, 418], - [5, 419], - [5, 420], - [5, 421], - [5, 422], - [5, 423], - [5, 424], - [5, 425], - [5, 426], - [5, 427], - [5, 428], - [5, 429], - [5, 430], - [5, 431], - [5, 432], - [5, 433], - [5, 434], - [5, 435], - [5, 436], - [5, 437], - [5, 438], - [5, 439], - [5, 440], - [5, 441], - [5, 442], - [5, 443], - [5, 444], - [5, 445], - [5, 446], - [5, 447], - [5, 448], - [5, 449], - [5, 450], - [5, 451], - [5, 452], - [5, 453], - [5, 454], - [5, 455], - [5, 456], - [5, 457], - [5, 458], - [5, 459], - [5, 460], - [5, 461], - [5, 462], - [5, 463], - [5, 464], - [5, 465], - [5, 466], - [5, 467], - [5, 468], - [5, 469], - [5, 470], - [5, 471], - [5, 472], - [5, 473], - [5, 474], - [5, 475], - [5, 476], - [5, 477], - [5, 478], - [5, 479], - [5, 480], - [5, 481], - [5, 482], - [5, 483], - [5, 484], - [5, 485], - [5, 486], - [5, 487], - [5, 488], - [5, 489], - [5, 490], - [5, 491], - [5, 492], - [5, 493], - [5, 494], - [5, 495], - [5, 496], - [5, 497], - [5, 498], - [5, 499], - [5, 500], - [5, 501], - [5, 502], - [5, 503], - [6, 2], - [6, 3], - [6, 4], - [6, 5], - [6, 6], - [6, 7], - [6, 8], - [6, 9], - [6, 10], - [6, 11], - [6, 12], - [6, 13], - [6, 14], - [6, 15], - [6, 16], - [6, 17], - [6, 18], - [6, 19], - [6, 20], - [6, 21], - [6, 22], - [6, 23], - [6, 24], - [6, 25], - [6, 26], - [6, 27], - [6, 28], - [6, 29], - [6, 30], - [6, 31], - [6, 32], - [6, 33], - [6, 34], - [6, 35], - [6, 36], - [6, 37], - [6, 38], - [6, 39], - [6, 40], - [6, 41], - [6, 42], - [6, 43], - [6, 44], - [6, 45], - [6, 46], - [6, 47], - [6, 48], - [6, 49], - [6, 50], - [6, 51], - [6, 52], - [6, 53], - [6, 54], - [6, 55], - [6, 56], - [6, 57], - [6, 58], - [6, 59], - [6, 60], - [6, 61], - [6, 62], - [6, 63], - [6, 64], - [6, 65], - [6, 66], - [6, 67], - [6, 68], - [6, 69], - [6, 70], - [6, 71], - [6, 72], - [6, 73], - [6, 74], - [6, 75], - [6, 76], - [6, 77], - [6, 78], - [6, 79], - [6, 80], - [6, 81], - [6, 82], - [6, 83], - [6, 84], - [6, 85], - [6, 86], - [6, 87], - [6, 88], - [6, 89], - [6, 90], - [6, 91], - [6, 92], - [6, 93], - [6, 94], - [6, 95], - [6, 96], - [6, 97], - [6, 98], - [6, 99], - [6, 100], - [6, 101], - [6, 102], - [6, 103], - [6, 104], - [6, 105], - [6, 106], - [6, 107], - [6, 108], - [6, 109], - [6, 110], - [6, 111], - [6, 112], - [6, 113], - [6, 114], - [6, 115], - [6, 116], - [6, 117], - [6, 118], - [6, 119], - [6, 120], - [6, 121], - [6, 122], - [6, 123], - [6, 124], - [6, 125], - [6, 126], - [6, 127], - [6, 128], - [6, 129], - [6, 130], - [6, 131], - [6, 132], - [6, 133], - [6, 134], - [6, 135], - [6, 136], - [6, 137], - [6, 138], - [6, 139], - [6, 140], - [6, 141], - [6, 142], - [6, 143], - [6, 144], - [6, 145], - [6, 146], - [6, 147], - [6, 148], - [6, 149], - [6, 150], - [6, 151], - [6, 152], - [6, 153], - [6, 154], - [6, 155], - [6, 156], - [6, 157], - [6, 158], - [6, 159], - [6, 160], - [6, 161], - [6, 162], - [6, 163], - [6, 164], - [6, 165], - [6, 166], - [6, 167], - [6, 168], - [6, 169], - [6, 170], - [6, 171], - [6, 172], - [6, 173], - [6, 174], - [6, 175], - [6, 176], - [6, 177], - [6, 178], - [6, 179], - [6, 180], - [6, 181], - [6, 182], - [6, 183], - [6, 184], - [6, 185], - [6, 186], - [6, 187], - [6, 188], - [6, 189], - [6, 190], - [6, 191], - [6, 192], - [6, 193], - [6, 194], - [6, 195], - [6, 196], - [6, 197], - [6, 198], - [6, 199], - [6, 200], - [6, 201], - [6, 202], - [6, 203], - [6, 204], - [6, 205], - [6, 206], - [6, 207], - [6, 208], - [6, 209], - [6, 210], - [6, 211], - [6, 212], - [6, 213], - [6, 214], - [6, 215], - [6, 216], - [6, 217], - [6, 218], - [6, 219], - [6, 220], - [6, 221], - [6, 222], - [6, 223], - [6, 224], - [6, 225], - [6, 226], - [6, 227], - [6, 228], - [6, 229], - [6, 230], - [6, 231], - [6, 232], - [6, 233], - [6, 234], - [6, 235], - [6, 236], - [6, 237], - [6, 238], - [6, 239], - [6, 240], - [6, 241], - [6, 242], - [6, 243], - [6, 244], - [6, 245], - [6, 246], - [6, 247], - [6, 248], - [6, 249], - [6, 250], - [6, 251], - [6, 252], - [6, 253], - [6, 254], - [6, 255], - [6, 256], - [6, 257], - [6, 258], - [6, 259], - [6, 260], - [6, 261], - [6, 262], - [6, 263], - [6, 264], - [6, 265], - [6, 266], - [6, 267], - [6, 268], - [6, 269], - [6, 270], - [6, 271], - [6, 272], - [6, 273], - [6, 274], - [6, 275], - [6, 276], - [6, 277], - [6, 278], - [6, 279], - [6, 280], - [6, 281], - [6, 282], - [6, 283], - [6, 284], - [6, 285], - [6, 286], - [6, 287], - [6, 288], - [6, 289], - [6, 290], - [6, 291], - [6, 292], - [6, 293], - [6, 294], - [6, 295], - [6, 296], - [6, 297], - [6, 298], - [6, 299], - [6, 300], - [6, 301], - [6, 302], - [6, 303], - [6, 304], - [6, 305], - [6, 306], - [6, 307], - [6, 308], - [6, 309], - [6, 310], - [6, 311], - [6, 312], - [6, 313], - [6, 314], - [6, 315], - [6, 316], - [6, 317], - [6, 318], - [6, 319], - [6, 320], - [6, 321], - [6, 322], - [6, 323], - [6, 324], - [6, 325], - [6, 326], - [6, 327], - [6, 328], - [6, 329], - [6, 330], - [6, 331], - [6, 332], - [6, 333], - [6, 334], - [6, 335], - [6, 336], - [6, 337], - [6, 338], - [6, 339], - [6, 340], - [6, 341], - [6, 342], - [6, 343], - [6, 344], - [6, 345], - [6, 346], - [6, 347], - [6, 348], - [6, 349], - [6, 350], - [6, 351], - [6, 352], - [6, 353], - [6, 354], - [6, 355], - [6, 356], - [6, 357], - [6, 358], - [6, 359], - [6, 360], - [6, 361], - [6, 362], - [6, 363], - [6, 364], - [6, 365], - [6, 366], - [6, 367], - [6, 368], - [6, 369], - [6, 370], - [6, 371], - [6, 372], - [6, 373], - [6, 374], - [6, 375], - [6, 376], - [6, 377], - [6, 378], - [6, 379], - [6, 380], - [6, 381], - [6, 382], - [6, 383], - [6, 384], - [6, 385], - [6, 386], - [6, 387], - [6, 388], - [6, 389], - [6, 390], - [6, 391], - [6, 392], - [6, 393], - [6, 394], - [6, 395], - [6, 396], - [6, 397], - [6, 398], - [6, 399], - [6, 400], - [6, 401], - [6, 402], - [6, 403], - [6, 404], - [6, 405], - [6, 406], - [6, 407], - [6, 408], - [6, 409], - [6, 410], - [6, 411], - [6, 412], - [6, 413], - [6, 414], - [6, 415], - [6, 416], - [6, 417], - [6, 418], - [6, 419], - [6, 420], - [6, 421], - [6, 422], - [6, 423], - [6, 424], - [6, 425], - [6, 426], - [6, 427], - [6, 428], - [6, 429], - [6, 430], - [6, 431], - [6, 432], - [6, 433], - [6, 434], - [6, 435], - [6, 436], - [6, 437], - [6, 438], - [6, 439], - [6, 440], - [6, 441], - [6, 442], - [6, 443], - [6, 444], - [6, 445], - [6, 446], - [6, 447], - [6, 448], - [6, 449], - [6, 450], - [6, 451], - [6, 452], - [6, 453], - [6, 454], - [6, 455], - [6, 456], - [6, 457], - [6, 458], - [6, 459], - [6, 460], - [6, 461], - [6, 462], - [6, 463], - [6, 464], - [6, 465], - [6, 466], - [6, 467], - [6, 468], - [6, 469], - [6, 470], - [6, 471], - [6, 472], - [6, 473], - [6, 474], - [6, 475], - [6, 476], - [6, 477], - [6, 478], - [6, 479], - [6, 480], - [6, 481], - [6, 482], - [6, 483], - [6, 484], - [6, 485], - [6, 486], - [6, 487], - [6, 488], - [6, 489], - [6, 490], - [6, 491], - [6, 492], - [6, 493], - [6, 494], - [6, 495], - [6, 496], - [6, 497], - [6, 498], - [6, 499], - [6, 500], - [6, 501], - [6, 502], - [6, 503], - [7, 2], - [7, 3], - [7, 4], - [7, 5], - [7, 6], - [7, 7], - [7, 8], - [7, 9], - [7, 10], - [7, 11], - [7, 12], - [7, 13], - [7, 14], - [7, 15], - [7, 16], - [7, 17], - [7, 18], - [7, 19], - [7, 20], - [7, 21], - [7, 22], - [7, 23], - [7, 24], - [7, 25], - [7, 26], - [7, 27], - [7, 28], - [7, 29], - [7, 30], - [7, 31], - [7, 32], - [7, 33], - [7, 34], - [7, 35], - [7, 36], - [7, 37], - [7, 38], - [7, 39], - [7, 40], - [7, 41], - [7, 42], - [7, 43], - [7, 44], - [7, 45], - [7, 46], - [7, 47], - [7, 48], - [7, 49], - [7, 50], - [7, 51], - [7, 52], - [7, 53], - [7, 54], - [7, 55], - [7, 56], - [7, 57], - [7, 58], - [7, 59], - [7, 60], - [7, 61], - [7, 62], - [7, 63], - [7, 64], - [7, 65], - [7, 66], - [7, 67], - [7, 68], - [7, 69], - [7, 70], - [7, 71], - [7, 72], - [7, 73], - [7, 74], - [7, 75], - [7, 76], - [7, 77], - [7, 78], - [7, 79], - [7, 80], - [7, 81], - [7, 82], - [7, 83], - [7, 84], - [7, 85], - [7, 86], - [7, 87], - [7, 88], - [7, 89], - [7, 90], - [7, 91], - [7, 92], - [7, 93], - [7, 94], - [7, 95], - [7, 96], - [7, 97], - [7, 98], - [7, 99], - [7, 100], - [7, 101], - [7, 102], - [7, 103], - [7, 104], - [7, 105], - [7, 106], - [7, 107], - [7, 108], - [7, 109], - [7, 110], - [7, 111], - [7, 112], - [7, 113], - [7, 114], - [7, 115], - [7, 116], - [7, 117], - [7, 118], - [7, 119], - [7, 120], - [7, 121], - [7, 122], - [7, 123], - [7, 124], - [7, 125], - [7, 126], - [7, 127], - [7, 128], - [7, 129], - [7, 130], - [7, 131], - [7, 132], - [7, 133], - [7, 134], - [7, 135], - [7, 136], - [7, 137], - [7, 138], - [7, 139], - [7, 140], - [7, 141], - [7, 142], - [7, 143], - [7, 144], - [7, 145], - [7, 146], - [7, 147], - [7, 148], - [7, 149], - [7, 150], - [7, 151], - [7, 152], - [7, 153], - [7, 154], - [7, 155], - [7, 156], - [7, 157], - [7, 158], - [7, 159], - [7, 160], - [7, 161], - [7, 162], - [7, 163], - [7, 164], - [7, 165], - [7, 166], - [7, 167], - [7, 168], - [7, 169], - [7, 170], - [7, 171], - [7, 172], - [7, 173], - [7, 174], - [7, 175], - [7, 176], - [7, 177], - [7, 178], - [7, 179], - [7, 180], - [7, 181], - [7, 182], - [7, 183], - [7, 184], - [7, 185], - [7, 186], - [7, 187], - [7, 188], - [7, 189], - [7, 190], - [7, 191], - [7, 192], - [7, 193], - [7, 194], - [7, 195], - [7, 196], - [7, 197], - [7, 198], - [7, 199], - [7, 200], - [7, 201], - [7, 202], - [7, 203], - [7, 204], - [7, 205], - [7, 206], - [7, 207], - [7, 208], - [7, 209], - [7, 210], - [7, 211], - [7, 212], - [7, 213], - [7, 214], - [7, 215], - [7, 216], - [7, 217], - [7, 218], - [7, 219], - [7, 220], - [7, 221], - [7, 222], - [7, 223], - [7, 224], - [7, 225], - [7, 226], - [7, 227], - [7, 228], - [7, 229], - [7, 230], - [7, 231], - [7, 232], - [7, 233], - [7, 234], - [7, 235], - [7, 236], - [7, 237], - [7, 238], - [7, 239], - [7, 240], - [7, 241], - [7, 242], - [7, 243], - [7, 244], - [7, 245], - [7, 246], - [7, 247], - [7, 248], - [7, 249], - [7, 250], - [7, 251], - [7, 252], - [7, 253], - [7, 254], - [7, 255], - [7, 256], - [7, 257], - [7, 258], - [7, 259], - [7, 260], - [7, 261], - [7, 262], - [7, 263], - [7, 264], - [7, 265], - [7, 266], - [7, 267], - [7, 268], - [7, 269], - [7, 270], - [7, 271], - [7, 272], - [7, 273], - [7, 274], - [7, 275], - [7, 276], - [7, 277], - [7, 278], - [7, 279], - [7, 280], - [7, 281], - [7, 282], - [7, 283], - [7, 284], - [7, 285], - [7, 286], - [7, 287], - [7, 288], - [7, 289], - [7, 290], - [7, 291], - [7, 292], - [7, 293], - [7, 294], - [7, 295], - [7, 296], - [7, 297], - [7, 298], - [7, 299], - [7, 300], - [7, 301], - [7, 302], - [7, 303], - [7, 304], - [7, 305], - [7, 306], - [7, 307], - [7, 308], - [7, 309], - [7, 310], - [7, 311], - [7, 312], - [7, 313], - [7, 314], - [7, 315], - [7, 316], - [7, 317], - [7, 318], - [7, 319], - [7, 320], - [7, 321], - [7, 322], - [7, 323], - [7, 324], - [7, 325], - [7, 326], - [7, 327], - [7, 328], - [7, 329], - [7, 330], - [7, 331], - [7, 332], - [7, 333], - [7, 334], - [7, 335], - [7, 336], - [7, 337], - [7, 338], - [7, 339], - [7, 340], - [7, 341], - [7, 342], - [7, 343], - [7, 344], - [7, 345], - [7, 346], - [7, 347], - [7, 348], - [7, 349], - [7, 350], - [7, 351], - [7, 352], - [7, 353], - [7, 354], - [7, 355], - [7, 356], - [7, 357], - [7, 358], - [7, 359], - [7, 360], - [7, 361], - [7, 362], - [7, 363], - [7, 364], - [7, 365], - [7, 366], - [7, 367], - [7, 368], - [7, 369], - [7, 370], - [7, 371], - [7, 372], - [7, 373], - [7, 374], - [7, 375], - [7, 376], - [7, 377], - [7, 378], - [7, 379], - [7, 380], - [7, 381], - [7, 382], - [7, 383], - [7, 384], - [7, 385], - [7, 386], - [7, 387], - [7, 388], - [7, 389], - [7, 390], - [7, 391], - [7, 392], - [7, 393], - [7, 394], - [7, 395], - [7, 396], - [7, 397], - [7, 398], - [7, 399], - [7, 400], - [7, 401], - [7, 402], - [7, 403], - [7, 404], - [7, 405], - [7, 406], - [7, 407], - [7, 408], - [7, 409], - [7, 410], - [7, 411], - [7, 412], - [7, 413], - [7, 414], - [7, 415], - [7, 416], - [7, 417], - [7, 418], - [7, 419], - [7, 420], - [7, 421], - [7, 422], - [7, 423], - [7, 424], - [7, 425], - [7, 426], - [7, 427], - [7, 428], - [7, 429], - [7, 430], - [7, 431], - [7, 432], - [7, 433], - [7, 434], - [7, 435], - [7, 436], - [7, 437], - [7, 438], - [7, 439], - [7, 440], - [7, 441], - [7, 442], - [7, 443], - [7, 444], - [7, 445], - [7, 446], - [7, 447], - [7, 448], - [7, 449], - [7, 450], - [7, 451], - [7, 452], - [7, 453], - [7, 454], - [7, 455], - [7, 456], - [7, 457], - [7, 458], - [7, 459], - [7, 460], - [7, 461], - [7, 462], - [7, 463], - [7, 464], - [7, 465], - [7, 466], - [7, 467], - [7, 468], - [7, 469], - [7, 470], - [7, 471], - [7, 472], - [7, 473], - [7, 474], - [7, 475], - [7, 476], - [7, 477], - [7, 478], - [7, 479], - [7, 480], - [7, 481], - [7, 482], - [7, 483], - [7, 484], - [7, 485], - [7, 486], - [7, 487], - [7, 488], - [7, 489], - [7, 490], - [7, 491], - [7, 492], - [7, 493], - [7, 494], - [7, 495], - [7, 496], - [7, 497], - [7, 498], - [7, 499], - [7, 500], - [7, 501], - [7, 502], - [7, 503], - [11, 3] - ], - "array_output": [ - ["2", "00V", "Meadow Lake", "Colorado Springs", "CO", "USA", "38.94574889", "-104.5698933"] - ], - "formatted_code": "df = getCells((0, 2), (7, 503), first_row_header=True)\ndf = df[df[\"iata\"] == c(11, 3)]\ndf = df.fillna('')\ndf.columns = range(df.columns.size)\ndf\n", - "error_span": null - }, - "dependent_cells": [ - [0, 2], - [0, 3], - [0, 4], - [0, 5], - [0, 6], - [0, 7], - [0, 8], - [0, 9], - [0, 10], - [0, 11], - [0, 12], - [0, 13], - [0, 14], - [0, 15], - [0, 16], - [0, 17], - [0, 18], - [0, 19], - [0, 20], - [0, 21], - [0, 22], - [0, 23], - [0, 24], - [0, 25], - [0, 26], - [0, 27], - [0, 28], - [0, 29], - [0, 30], - [0, 31], - [0, 32], - [0, 33], - [0, 34], - [0, 35], - [0, 36], - [0, 37], - [0, 38], - [0, 39], - [0, 40], - [0, 41], - [0, 42], - [0, 43], - [0, 44], - [0, 45], - [0, 46], - [0, 47], - [0, 48], - [0, 49], - [0, 50], - [0, 51], - [0, 52], - [0, 53], - [0, 54], - [0, 55], - [0, 56], - [0, 57], - [0, 58], - [0, 59], - [0, 60], - [0, 61], - [0, 62], - [0, 63], - [0, 64], - [0, 65], - [0, 66], - [0, 67], - [0, 68], - [0, 69], - [0, 70], - [0, 71], - [0, 72], - [0, 73], - [0, 74], - [0, 75], - [0, 76], - [0, 77], - [0, 78], - [0, 79], - [0, 80], - [0, 81], - [0, 82], - [0, 83], - [0, 84], - [0, 85], - [0, 86], - [0, 87], - [0, 88], - [0, 89], - [0, 90], - [0, 91], - [0, 92], - [0, 93], - [0, 94], - [0, 95], - [0, 96], - [0, 97], - [0, 98], - [0, 99], - [0, 100], - [0, 101], - [0, 102], - [0, 103], - [0, 104], - [0, 105], - [0, 106], - [0, 107], - [0, 108], - [0, 109], - [0, 110], - [0, 111], - [0, 112], - [0, 113], - [0, 114], - [0, 115], - [0, 116], - [0, 117], - [0, 118], - [0, 119], - [0, 120], - [0, 121], - [0, 122], - [0, 123], - [0, 124], - [0, 125], - [0, 126], - [0, 127], - [0, 128], - [0, 129], - [0, 130], - [0, 131], - [0, 132], - [0, 133], - [0, 134], - [0, 135], - [0, 136], - [0, 137], - [0, 138], - [0, 139], - [0, 140], - [0, 141], - [0, 142], - [0, 143], - [0, 144], - [0, 145], - [0, 146], - [0, 147], - [0, 148], - [0, 149], - [0, 150], - [0, 151], - [0, 152], - [0, 153], - [0, 154], - [0, 155], - [0, 156], - [0, 157], - [0, 158], - [0, 159], - [0, 160], - [0, 161], - [0, 162], - [0, 163], - [0, 164], - [0, 165], - [0, 166], - [0, 167], - [0, 168], - [0, 169], - [0, 170], - [0, 171], - [0, 172], - [0, 173], - [0, 174], - [0, 175], - [0, 176], - [0, 177], - [0, 178], - [0, 179], - [0, 180], - [0, 181], - [0, 182], - [0, 183], - [0, 184], - [0, 185], - [0, 186], - [0, 187], - [0, 188], - [0, 189], - [0, 190], - [0, 191], - [0, 192], - [0, 193], - [0, 194], - [0, 195], - [0, 196], - [0, 197], - [0, 198], - [0, 199], - [0, 200], - [0, 201], - [0, 202], - [0, 203], - [0, 204], - [0, 205], - [0, 206], - [0, 207], - [0, 208], - [0, 209], - [0, 210], - [0, 211], - [0, 212], - [0, 213], - [0, 214], - [0, 215], - [0, 216], - [0, 217], - [0, 218], - [0, 219], - [0, 220], - [0, 221], - [0, 222], - [0, 223], - [0, 224], - [0, 225], - [0, 226], - [0, 227], - [0, 228], - [0, 229], - [0, 230], - [0, 231], - [0, 232], - [0, 233], - [0, 234], - [0, 235], - [0, 236], - [0, 237], - [0, 238], - [0, 239], - [0, 240], - [0, 241], - [0, 242], - [0, 243], - [0, 244], - [0, 245], - [0, 246], - [0, 247], - [0, 248], - [0, 249], - [0, 250], - [0, 251], - [0, 252], - [0, 253], - [0, 254], - [0, 255], - [0, 256], - [0, 257], - [0, 258], - [0, 259], - [0, 260], - [0, 261], - [0, 262], - [0, 263], - [0, 264], - [0, 265], - [0, 266], - [0, 267], - [0, 268], - [0, 269], - [0, 270], - [0, 271], - [0, 272], - [0, 273], - [0, 274], - [0, 275], - [0, 276], - [0, 277], - [0, 278], - [0, 279], - [0, 280], - [0, 281], - [0, 282], - [0, 283], - [0, 284], - [0, 285], - [0, 286], - [0, 287], - [0, 288], - [0, 289], - [0, 290], - [0, 291], - [0, 292], - [0, 293], - [0, 294], - [0, 295], - [0, 296], - [0, 297], - [0, 298], - [0, 299], - [0, 300], - [0, 301], - [0, 302], - [0, 303], - [0, 304], - [0, 305], - [0, 306], - [0, 307], - [0, 308], - [0, 309], - [0, 310], - [0, 311], - [0, 312], - [0, 313], - [0, 314], - [0, 315], - [0, 316], - [0, 317], - [0, 318], - [0, 319], - [0, 320], - [0, 321], - [0, 322], - [0, 323], - [0, 324], - [0, 325], - [0, 326], - [0, 327], - [0, 328], - [0, 329], - [0, 330], - [0, 331], - [0, 332], - [0, 333], - [0, 334], - [0, 335], - [0, 336], - [0, 337], - [0, 338], - [0, 339], - [0, 340], - [0, 341], - [0, 342], - [0, 343], - [0, 344], - [0, 345], - [0, 346], - [0, 347], - [0, 348], - [0, 349], - [0, 350], - [0, 351], - [0, 352], - [0, 353], - [0, 354], - [0, 355], - [0, 356], - [0, 357], - [0, 358], - [0, 359], - [0, 360], - [0, 361], - [0, 362], - [0, 363], - [0, 364], - [0, 365], - [0, 366], - [0, 367], - [0, 368], - [0, 369], - [0, 370], - [0, 371], - [0, 372], - [0, 373], - [0, 374], - [0, 375], - [0, 376], - [0, 377], - [0, 378], - [0, 379], - [0, 380], - [0, 381], - [0, 382], - [0, 383], - [0, 384], - [0, 385], - [0, 386], - [0, 387], - [0, 388], - [0, 389], - [0, 390], - [0, 391], - [0, 392], - [0, 393], - [0, 394], - [0, 395], - [0, 396], - [0, 397], - [0, 398], - [0, 399], - [0, 400], - [0, 401], - [0, 402], - [0, 403], - [0, 404], - [0, 405], - [0, 406], - [0, 407], - [0, 408], - [0, 409], - [0, 410], - [0, 411], - [0, 412], - [0, 413], - [0, 414], - [0, 415], - [0, 416], - [0, 417], - [0, 418], - [0, 419], - [0, 420], - [0, 421], - [0, 422], - [0, 423], - [0, 424], - [0, 425], - [0, 426], - [0, 427], - [0, 428], - [0, 429], - [0, 430], - [0, 431], - [0, 432], - [0, 433], - [0, 434], - [0, 435], - [0, 436], - [0, 437], - [0, 438], - [0, 439], - [0, 440], - [0, 441], - [0, 442], - [0, 443], - [0, 444], - [0, 445], - [0, 446], - [0, 447], - [0, 448], - [0, 449], - [0, 450], - [0, 451], - [0, 452], - [0, 453], - [0, 454], - [0, 455], - [0, 456], - [0, 457], - [0, 458], - [0, 459], - [0, 460], - [0, 461], - [0, 462], - [0, 463], - [0, 464], - [0, 465], - [0, 466], - [0, 467], - [0, 468], - [0, 469], - [0, 470], - [0, 471], - [0, 472], - [0, 473], - [0, 474], - [0, 475], - [0, 476], - [0, 477], - [0, 478], - [0, 479], - [0, 480], - [0, 481], - [0, 482], - [0, 483], - [0, 484], - [0, 485], - [0, 486], - [0, 487], - [0, 488], - [0, 489], - [0, 490], - [0, 491], - [0, 492], - [0, 493], - [0, 494], - [0, 495], - [0, 496], - [0, 497], - [0, 498], - [0, 499], - [0, 500], - [1, 2], - [1, 3], - [1, 4], - [1, 5], - [1, 6], - [1, 7], - [1, 8], - [1, 9], - [1, 10], - [1, 11], - [1, 12], - [1, 13], - [1, 14], - [1, 15], - [1, 16], - [1, 17], - [1, 18], - [1, 19], - [1, 20], - [1, 21], - [1, 22], - [1, 23], - [1, 24], - [1, 25], - [1, 26], - [1, 27], - [1, 28], - [1, 29], - [1, 30], - [1, 31], - [1, 32], - [1, 33], - [1, 34], - [1, 35], - [1, 36], - [1, 37], - [1, 38], - [1, 39], - [1, 40], - [1, 41], - [1, 42], - [1, 43], - [1, 44], - [1, 45], - [1, 46], - [1, 47], - [1, 48], - [1, 49], - [1, 50], - [1, 51], - [1, 52], - [1, 53], - [1, 54], - [1, 55], - [1, 56], - [1, 57], - [1, 58], - [1, 59], - [1, 60], - [1, 61], - [1, 62], - [1, 63], - [1, 64], - [1, 65], - [1, 66], - [1, 67], - [1, 68], - [1, 69], - [1, 70], - [1, 71], - [1, 72], - [1, 73], - [1, 74], - [1, 75], - [1, 76], - [1, 77], - [1, 78], - [1, 79], - [1, 80], - [1, 81], - [1, 82], - [1, 83], - [1, 84], - [1, 85], - [1, 86], - [1, 87], - [1, 88], - [1, 89], - [1, 90], - [1, 91], - [1, 92], - [1, 93], - [1, 94], - [1, 95], - [1, 96], - [1, 97], - [1, 98], - [1, 99], - [1, 100], - [1, 101], - [1, 102], - [1, 103], - [1, 104], - [1, 105], - [1, 106], - [1, 107], - [1, 108], - [1, 109], - [1, 110], - [1, 111], - [1, 112], - [1, 113], - [1, 114], - [1, 115], - [1, 116], - [1, 117], - [1, 118], - [1, 119], - [1, 120], - [1, 121], - [1, 122], - [1, 123], - [1, 124], - [1, 125], - [1, 126], - [1, 127], - [1, 128], - [1, 129], - [1, 130], - [1, 131], - [1, 132], - [1, 133], - [1, 134], - [1, 135], - [1, 136], - [1, 137], - [1, 138], - [1, 139], - [1, 140], - [1, 141], - [1, 142], - [1, 143], - [1, 144], - [1, 145], - [1, 146], - [1, 147], - [1, 148], - [1, 149], - [1, 150], - [1, 151], - [1, 152], - [1, 153], - [1, 154], - [1, 155], - [1, 156], - [1, 157], - [1, 158], - [1, 159], - [1, 160], - [1, 161], - [1, 162], - [1, 163], - [1, 164], - [1, 165], - [1, 166], - [1, 167], - [1, 168], - [1, 169], - [1, 170], - [1, 171], - [1, 172], - [1, 173], - [1, 174], - [1, 175], - [1, 176], - [1, 177], - [1, 178], - [1, 179], - [1, 180], - [1, 181], - [1, 182], - [1, 183], - [1, 184], - [1, 185], - [1, 186], - [1, 187], - [1, 188], - [1, 189], - [1, 190], - [1, 191], - [1, 192], - [1, 193], - [1, 194], - [1, 195], - [1, 196], - [1, 197], - [1, 198], - [1, 199], - [1, 200], - [1, 201], - [1, 202], - [1, 203], - [1, 204], - [1, 205], - [1, 206], - [1, 207], - [1, 208], - [1, 209], - [1, 210], - [1, 211], - [1, 212], - [1, 213], - [1, 214], - [1, 215], - [1, 216], - [1, 217], - [1, 218], - [1, 219], - [1, 220], - [1, 221], - [1, 222], - [1, 223], - [1, 224], - [1, 225], - [1, 226], - [1, 227], - [1, 228], - [1, 229], - [1, 230], - [1, 231], - [1, 232], - [1, 233], - [1, 234], - [1, 235], - [1, 236], - [1, 237], - [1, 238], - [1, 239], - [1, 240], - [1, 241], - [1, 242], - [1, 243], - [1, 244], - [1, 245], - [1, 246], - [1, 247], - [1, 248], - [1, 249], - [1, 250], - [1, 251], - [1, 252], - [1, 253], - [1, 254], - [1, 255], - [1, 256], - [1, 257], - [1, 258], - [1, 259], - [1, 260], - [1, 261], - [1, 262], - [1, 263], - [1, 264], - [1, 265], - [1, 266], - [1, 267], - [1, 268], - [1, 269], - [1, 270], - [1, 271], - [1, 272], - [1, 273], - [1, 274], - [1, 275], - [1, 276], - [1, 277], - [1, 278], - [1, 279], - [1, 280], - [1, 281], - [1, 282], - [1, 283], - [1, 284], - [1, 285], - [1, 286], - [1, 287], - [1, 288], - [1, 289], - [1, 290], - [1, 291], - [1, 292], - [1, 293], - [1, 294], - [1, 295], - [1, 296], - [1, 297], - [1, 298], - [1, 299], - [1, 300], - [1, 301], - [1, 302], - [1, 303], - [1, 304], - [1, 305], - [1, 306], - [1, 307], - [1, 308], - [1, 309], - [1, 310], - [1, 311], - [1, 312], - [1, 313], - [1, 314], - [1, 315], - [1, 316], - [1, 317], - [1, 318], - [1, 319], - [1, 320], - [1, 321], - [1, 322], - [1, 323], - [1, 324], - [1, 325], - [1, 326], - [1, 327], - [1, 328], - [1, 329], - [1, 330], - [1, 331], - [1, 332], - [1, 333], - [1, 334], - [1, 335], - [1, 336], - [1, 337], - [1, 338], - [1, 339], - [1, 340], - [1, 341], - [1, 342], - [1, 343], - [1, 344], - [1, 345], - [1, 346], - [1, 347], - [1, 348], - [1, 349], - [1, 350], - [1, 351], - [1, 352], - [1, 353], - [1, 354], - [1, 355], - [1, 356], - [1, 357], - [1, 358], - [1, 359], - [1, 360], - [1, 361], - [1, 362], - [1, 363], - [1, 364], - [1, 365], - [1, 366], - [1, 367], - [1, 368], - [1, 369], - [1, 370], - [1, 371], - [1, 372], - [1, 373], - [1, 374], - [1, 375], - [1, 376], - [1, 377], - [1, 378], - [1, 379], - [1, 380], - [1, 381], - [1, 382], - [1, 383], - [1, 384], - [1, 385], - [1, 386], - [1, 387], - [1, 388], - [1, 389], - [1, 390], - [1, 391], - [1, 392], - [1, 393], - [1, 394], - [1, 395], - [1, 396], - [1, 397], - [1, 398], - [1, 399], - [1, 400], - [1, 401], - [1, 402], - [1, 403], - [1, 404], - [1, 405], - [1, 406], - [1, 407], - [1, 408], - [1, 409], - [1, 410], - [1, 411], - [1, 412], - [1, 413], - [1, 414], - [1, 415], - [1, 416], - [1, 417], - [1, 418], - [1, 419], - [1, 420], - [1, 421], - [1, 422], - [1, 423], - [1, 424], - [1, 425], - [1, 426], - [1, 427], - [1, 428], - [1, 429], - [1, 430], - [1, 431], - [1, 432], - [1, 433], - [1, 434], - [1, 435], - [1, 436], - [1, 437], - [1, 438], - [1, 439], - [1, 440], - [1, 441], - [1, 442], - [1, 443], - [1, 444], - [1, 445], - [1, 446], - [1, 447], - [1, 448], - [1, 449], - [1, 450], - [1, 451], - [1, 452], - [1, 453], - [1, 454], - [1, 455], - [1, 456], - [1, 457], - [1, 458], - [1, 459], - [1, 460], - [1, 461], - [1, 462], - [1, 463], - [1, 464], - [1, 465], - [1, 466], - [1, 467], - [1, 468], - [1, 469], - [1, 470], - [1, 471], - [1, 472], - [1, 473], - [1, 474], - [1, 475], - [1, 476], - [1, 477], - [1, 478], - [1, 479], - [1, 480], - [1, 481], - [1, 482], - [1, 483], - [1, 484], - [1, 485], - [1, 486], - [1, 487], - [1, 488], - [1, 489], - [1, 490], - [1, 491], - [1, 492], - [1, 493], - [1, 494], - [1, 495], - [1, 496], - [1, 497], - [1, 498], - [1, 499], - [1, 500], - [2, 2], - [2, 3], - [2, 4], - [2, 5], - [2, 6], - [2, 7], - [2, 8], - [2, 9], - [2, 10], - [2, 11], - [2, 12], - [2, 13], - [2, 14], - [2, 15], - [2, 16], - [2, 17], - [2, 18], - [2, 19], - [2, 20], - [2, 21], - [2, 22], - [2, 23], - [2, 24], - [2, 25], - [2, 26], - [2, 27], - [2, 28], - [2, 29], - [2, 30], - [2, 31], - [2, 32], - [2, 33], - [2, 34], - [2, 35], - [2, 36], - [2, 37], - [2, 38], - [2, 39], - [2, 40], - [2, 41], - [2, 42], - [2, 43], - [2, 44], - [2, 45], - [2, 46], - [2, 47], - [2, 48], - [2, 49], - [2, 50], - [2, 51], - [2, 52], - [2, 53], - [2, 54], - [2, 55], - [2, 56], - [2, 57], - [2, 58], - [2, 59], - [2, 60], - [2, 61], - [2, 62], - [2, 63], - [2, 64], - [2, 65], - [2, 66], - [2, 67], - [2, 68], - [2, 69], - [2, 70], - [2, 71], - [2, 72], - [2, 73], - [2, 74], - [2, 75], - [2, 76], - [2, 77], - [2, 78], - [2, 79], - [2, 80], - [2, 81], - [2, 82], - [2, 83], - [2, 84], - [2, 85], - [2, 86], - [2, 87], - [2, 88], - [2, 89], - [2, 90], - [2, 91], - [2, 92], - [2, 93], - [2, 94], - [2, 95], - [2, 96], - [2, 97], - [2, 98], - [2, 99], - [2, 100], - [2, 101], - [2, 102], - [2, 103], - [2, 104], - [2, 105], - [2, 106], - [2, 107], - [2, 108], - [2, 109], - [2, 110], - [2, 111], - [2, 112], - [2, 113], - [2, 114], - [2, 115], - [2, 116], - [2, 117], - [2, 118], - [2, 119], - [2, 120], - [2, 121], - [2, 122], - [2, 123], - [2, 124], - [2, 125], - [2, 126], - [2, 127], - [2, 128], - [2, 129], - [2, 130], - [2, 131], - [2, 132], - [2, 133], - [2, 134], - [2, 135], - [2, 136], - [2, 137], - [2, 138], - [2, 139], - [2, 140], - [2, 141], - [2, 142], - [2, 143], - [2, 144], - [2, 145], - [2, 146], - [2, 147], - [2, 148], - [2, 149], - [2, 150], - [2, 151], - [2, 152], - [2, 153], - [2, 154], - [2, 155], - [2, 156], - [2, 157], - [2, 158], - [2, 159], - [2, 160], - [2, 161], - [2, 162], - [2, 163], - [2, 164], - [2, 165], - [2, 166], - [2, 167], - [2, 168], - [2, 169], - [2, 170], - [2, 171], - [2, 172], - [2, 173], - [2, 174], - [2, 175], - [2, 176], - [2, 177], - [2, 178], - [2, 179], - [2, 180], - [2, 181], - [2, 182], - [2, 183], - [2, 184], - [2, 185], - [2, 186], - [2, 187], - [2, 188], - [2, 189], - [2, 190], - [2, 191], - [2, 192], - [2, 193], - [2, 194], - [2, 195], - [2, 196], - [2, 197], - [2, 198], - [2, 199], - [2, 200], - [2, 201], - [2, 202], - [2, 203], - [2, 204], - [2, 205], - [2, 206], - [2, 207], - [2, 208], - [2, 209], - [2, 210], - [2, 211], - [2, 212], - [2, 213], - [2, 214], - [2, 215], - [2, 216], - [2, 217], - [2, 218], - [2, 219], - [2, 220], - [2, 221], - [2, 222], - [2, 223], - [2, 224], - [2, 225], - [2, 226], - [2, 227], - [2, 228], - [2, 229], - [2, 230], - [2, 231], - [2, 232], - [2, 233], - [2, 234], - [2, 235], - [2, 236], - [2, 237], - [2, 238], - [2, 239], - [2, 240], - [2, 241], - [2, 242], - [2, 243], - [2, 244], - [2, 245], - [2, 246], - [2, 247], - [2, 248], - [2, 249], - [2, 250], - [2, 251], - [2, 252], - [2, 253], - [2, 254], - [2, 255], - [2, 256], - [2, 257], - [2, 258], - [2, 259], - [2, 260], - [2, 261], - [2, 262], - [2, 263], - [2, 264], - [2, 265], - [2, 266], - [2, 267], - [2, 268], - [2, 269], - [2, 270], - [2, 271], - [2, 272], - [2, 273], - [2, 274], - [2, 275], - [2, 276], - [2, 277], - [2, 278], - [2, 279], - [2, 280], - [2, 281], - [2, 282], - [2, 283], - [2, 284], - [2, 285], - [2, 286], - [2, 287], - [2, 288], - [2, 289], - [2, 290], - [2, 291], - [2, 292], - [2, 293], - [2, 294], - [2, 295], - [2, 296], - [2, 297], - [2, 298], - [2, 299], - [2, 300], - [2, 301], - [2, 302], - [2, 303], - [2, 304], - [2, 305], - [2, 306], - [2, 307], - [2, 308], - [2, 309], - [2, 310], - [2, 311], - [2, 312], - [2, 313], - [2, 314], - [2, 315], - [2, 316], - [2, 317], - [2, 318], - [2, 319], - [2, 320], - [2, 321], - [2, 322], - [2, 323], - [2, 324], - [2, 325], - [2, 326], - [2, 327], - [2, 328], - [2, 329], - [2, 330], - [2, 331], - [2, 332], - [2, 333], - [2, 334], - [2, 335], - [2, 336], - [2, 337], - [2, 338], - [2, 339], - [2, 340], - [2, 341], - [2, 342], - [2, 343], - [2, 344], - [2, 345], - [2, 346], - [2, 347], - [2, 348], - [2, 349], - [2, 350], - [2, 351], - [2, 352], - [2, 353], - [2, 354], - [2, 355], - [2, 356], - [2, 357], - [2, 358], - [2, 359], - [2, 360], - [2, 361], - [2, 362], - [2, 363], - [2, 364], - [2, 365], - [2, 366], - [2, 367], - [2, 368], - [2, 369], - [2, 370], - [2, 371], - [2, 372], - [2, 373], - [2, 374], - [2, 375], - [2, 376], - [2, 377], - [2, 378], - [2, 379], - [2, 380], - [2, 381], - [2, 382], - [2, 383], - [2, 384], - [2, 385], - [2, 386], - [2, 387], - [2, 388], - [2, 389], - [2, 390], - [2, 391], - [2, 392], - [2, 393], - [2, 394], - [2, 395], - [2, 396], - [2, 397], - [2, 398], - [2, 399], - [2, 400], - [2, 401], - [2, 402], - [2, 403], - [2, 404], - [2, 405], - [2, 406], - [2, 407], - [2, 408], - [2, 409], - [2, 410], - [2, 411], - [2, 412], - [2, 413], - [2, 414], - [2, 415], - [2, 416], - [2, 417], - [2, 418], - [2, 419], - [2, 420], - [2, 421], - [2, 422], - [2, 423], - [2, 424], - [2, 425], - [2, 426], - [2, 427], - [2, 428], - [2, 429], - [2, 430], - [2, 431], - [2, 432], - [2, 433], - [2, 434], - [2, 435], - [2, 436], - [2, 437], - [2, 438], - [2, 439], - [2, 440], - [2, 441], - [2, 442], - [2, 443], - [2, 444], - [2, 445], - [2, 446], - [2, 447], - [2, 448], - [2, 449], - [2, 450], - [2, 451], - [2, 452], - [2, 453], - [2, 454], - [2, 455], - [2, 456], - [2, 457], - [2, 458], - [2, 459], - [2, 460], - [2, 461], - [2, 462], - [2, 463], - [2, 464], - [2, 465], - [2, 466], - [2, 467], - [2, 468], - [2, 469], - [2, 470], - [2, 471], - [2, 472], - [2, 473], - [2, 474], - [2, 475], - [2, 476], - [2, 477], - [2, 478], - [2, 479], - [2, 480], - [2, 481], - [2, 482], - [2, 483], - [2, 484], - [2, 485], - [2, 486], - [2, 487], - [2, 488], - [2, 489], - [2, 490], - [2, 491], - [2, 492], - [2, 493], - [2, 494], - [2, 495], - [2, 496], - [2, 497], - [2, 498], - [2, 499], - [2, 500], - [3, 2], - [3, 3], - [3, 4], - [3, 5], - [3, 6], - [3, 7], - [3, 8], - [3, 9], - [3, 10], - [3, 11], - [3, 12], - [3, 13], - [3, 14], - [3, 15], - [3, 16], - [3, 17], - [3, 18], - [3, 19], - [3, 20], - [3, 21], - [3, 22], - [3, 23], - [3, 24], - [3, 25], - [3, 26], - [3, 27], - [3, 28], - [3, 29], - [3, 30], - [3, 31], - [3, 32], - [3, 33], - [3, 34], - [3, 35], - [3, 36], - [3, 37], - [3, 38], - [3, 39], - [3, 40], - [3, 41], - [3, 42], - [3, 43], - [3, 44], - [3, 45], - [3, 46], - [3, 47], - [3, 48], - [3, 49], - [3, 50], - [3, 51], - [3, 52], - [3, 53], - [3, 54], - [3, 55], - [3, 56], - [3, 57], - [3, 58], - [3, 59], - [3, 60], - [3, 61], - [3, 62], - [3, 63], - [3, 64], - [3, 65], - [3, 66], - [3, 67], - [3, 68], - [3, 69], - [3, 70], - [3, 71], - [3, 72], - [3, 73], - [3, 74], - [3, 75], - [3, 76], - [3, 77], - [3, 78], - [3, 79], - [3, 80], - [3, 81], - [3, 82], - [3, 83], - [3, 84], - [3, 85], - [3, 86], - [3, 87], - [3, 88], - [3, 89], - [3, 90], - [3, 91], - [3, 92], - [3, 93], - [3, 94], - [3, 95], - [3, 96], - [3, 97], - [3, 98], - [3, 99], - [3, 100], - [3, 101], - [3, 102], - [3, 103], - [3, 104], - [3, 105], - [3, 106], - [3, 107], - [3, 108], - [3, 109], - [3, 110], - [3, 111], - [3, 112], - [3, 113], - [3, 114], - [3, 115], - [3, 116], - [3, 117], - [3, 118], - [3, 119], - [3, 120], - [3, 121], - [3, 122], - [3, 123], - [3, 124], - [3, 125], - [3, 126], - [3, 127], - [3, 128], - [3, 129], - [3, 130], - [3, 131], - [3, 132], - [3, 133], - [3, 134], - [3, 135], - [3, 136], - [3, 137], - [3, 138], - [3, 139], - [3, 140], - [3, 141], - [3, 142], - [3, 143], - [3, 144], - [3, 145], - [3, 146], - [3, 147], - [3, 148], - [3, 149], - [3, 150], - [3, 151], - [3, 152], - [3, 153], - [3, 154], - [3, 155], - [3, 156], - [3, 157], - [3, 158], - [3, 159], - [3, 160], - [3, 161], - [3, 162], - [3, 163], - [3, 164], - [3, 165], - [3, 166], - [3, 167], - [3, 168], - [3, 169], - [3, 170], - [3, 171], - [3, 172], - [3, 173], - [3, 174], - [3, 175], - [3, 176], - [3, 177], - [3, 178], - [3, 179], - [3, 180], - [3, 181], - [3, 182], - [3, 183], - [3, 184], - [3, 185], - [3, 186], - [3, 187], - [3, 188], - [3, 189], - [3, 190], - [3, 191], - [3, 192], - [3, 193], - [3, 194], - [3, 195], - [3, 196], - [3, 197], - [3, 198], - [3, 199], - [3, 200], - [3, 201], - [3, 202], - [3, 203], - [3, 204], - [3, 205], - [3, 206], - [3, 207], - [3, 208], - [3, 209], - [3, 210], - [3, 211], - [3, 212], - [3, 213], - [3, 214], - [3, 215], - [3, 216], - [3, 217], - [3, 218], - [3, 219], - [3, 220], - [3, 221], - [3, 222], - [3, 223], - [3, 224], - [3, 225], - [3, 226], - [3, 227], - [3, 228], - [3, 229], - [3, 230], - [3, 231], - [3, 232], - [3, 233], - [3, 234], - [3, 235], - [3, 236], - [3, 237], - [3, 238], - [3, 239], - [3, 240], - [3, 241], - [3, 242], - [3, 243], - [3, 244], - [3, 245], - [3, 246], - [3, 247], - [3, 248], - [3, 249], - [3, 250], - [3, 251], - [3, 252], - [3, 253], - [3, 254], - [3, 255], - [3, 256], - [3, 257], - [3, 258], - [3, 259], - [3, 260], - [3, 261], - [3, 262], - [3, 263], - [3, 264], - [3, 265], - [3, 266], - [3, 267], - [3, 268], - [3, 269], - [3, 270], - [3, 271], - [3, 272], - [3, 273], - [3, 274], - [3, 275], - [3, 276], - [3, 277], - [3, 278], - [3, 279], - [3, 280], - [3, 281], - [3, 282], - [3, 283], - [3, 284], - [3, 285], - [3, 286], - [3, 287], - [3, 288], - [3, 289], - [3, 290], - [3, 291], - [3, 292], - [3, 293], - [3, 294], - [3, 295], - [3, 296], - [3, 297], - [3, 298], - [3, 299], - [3, 300], - [3, 301], - [3, 302], - [3, 303], - [3, 304], - [3, 305], - [3, 306], - [3, 307], - [3, 308], - [3, 309], - [3, 310], - [3, 311], - [3, 312], - [3, 313], - [3, 314], - [3, 315], - [3, 316], - [3, 317], - [3, 318], - [3, 319], - [3, 320], - [3, 321], - [3, 322], - [3, 323], - [3, 324], - [3, 325], - [3, 326], - [3, 327], - [3, 328], - [3, 329], - [3, 330], - [3, 331], - [3, 332], - [3, 333], - [3, 334], - [3, 335], - [3, 336], - [3, 337], - [3, 338], - [3, 339], - [3, 340], - [3, 341], - [3, 342], - [3, 343], - [3, 344], - [3, 345], - [3, 346], - [3, 347], - [3, 348], - [3, 349], - [3, 350], - [3, 351], - [3, 352], - [3, 353], - [3, 354], - [3, 355], - [3, 356], - [3, 357], - [3, 358], - [3, 359], - [3, 360], - [3, 361], - [3, 362], - [3, 363], - [3, 364], - [3, 365], - [3, 366], - [3, 367], - [3, 368], - [3, 369], - [3, 370], - [3, 371], - [3, 372], - [3, 373], - [3, 374], - [3, 375], - [3, 376], - [3, 377], - [3, 378], - [3, 379], - [3, 380], - [3, 381], - [3, 382], - [3, 383], - [3, 384], - [3, 385], - [3, 386], - [3, 387], - [3, 388], - [3, 389], - [3, 390], - [3, 391], - [3, 392], - [3, 393], - [3, 394], - [3, 395], - [3, 396], - [3, 397], - [3, 398], - [3, 399], - [3, 400], - [3, 401], - [3, 402], - [3, 403], - [3, 404], - [3, 405], - [3, 406], - [3, 407], - [3, 408], - [3, 409], - [3, 410], - [3, 411], - [3, 412], - [3, 413], - [3, 414], - [3, 415], - [3, 416], - [3, 417], - [3, 418], - [3, 419], - [3, 420], - [3, 421], - [3, 422], - [3, 423], - [3, 424], - [3, 425], - [3, 426], - [3, 427], - [3, 428], - [3, 429], - [3, 430], - [3, 431], - [3, 432], - [3, 433], - [3, 434], - [3, 435], - [3, 436], - [3, 437], - [3, 438], - [3, 439], - [3, 440], - [3, 441], - [3, 442], - [3, 443], - [3, 444], - [3, 445], - [3, 446], - [3, 447], - [3, 448], - [3, 449], - [3, 450], - [3, 451], - [3, 452], - [3, 453], - [3, 454], - [3, 455], - [3, 456], - [3, 457], - [3, 458], - [3, 459], - [3, 460], - [3, 461], - [3, 462], - [3, 463], - [3, 464], - [3, 465], - [3, 466], - [3, 467], - [3, 468], - [3, 469], - [3, 470], - [3, 471], - [3, 472], - [3, 473], - [3, 474], - [3, 475], - [3, 476], - [3, 477], - [3, 478], - [3, 479], - [3, 480], - [3, 481], - [3, 482], - [3, 483], - [3, 484], - [3, 485], - [3, 486], - [3, 487], - [3, 488], - [3, 489], - [3, 490], - [3, 491], - [3, 492], - [3, 493], - [3, 494], - [3, 495], - [3, 496], - [3, 497], - [3, 498], - [3, 499], - [3, 500], - [4, 2], - [4, 3], - [4, 4], - [4, 5], - [4, 6], - [4, 7], - [4, 8], - [4, 9], - [4, 10], - [4, 11], - [4, 12], - [4, 13], - [4, 14], - [4, 15], - [4, 16], - [4, 17], - [4, 18], - [4, 19], - [4, 20], - [4, 21], - [4, 22], - [4, 23], - [4, 24], - [4, 25], - [4, 26], - [4, 27], - [4, 28], - [4, 29], - [4, 30], - [4, 31], - [4, 32], - [4, 33], - [4, 34], - [4, 35], - [4, 36], - [4, 37], - [4, 38], - [4, 39], - [4, 40], - [4, 41], - [4, 42], - [4, 43], - [4, 44], - [4, 45], - [4, 46], - [4, 47], - [4, 48], - [4, 49], - [4, 50], - [4, 51], - [4, 52], - [4, 53], - [4, 54], - [4, 55], - [4, 56], - [4, 57], - [4, 58], - [4, 59], - [4, 60], - [4, 61], - [4, 62], - [4, 63], - [4, 64], - [4, 65], - [4, 66], - [4, 67], - [4, 68], - [4, 69], - [4, 70], - [4, 71], - [4, 72], - [4, 73], - [4, 74], - [4, 75], - [4, 76], - [4, 77], - [4, 78], - [4, 79], - [4, 80], - [4, 81], - [4, 82], - [4, 83], - [4, 84], - [4, 85], - [4, 86], - [4, 87], - [4, 88], - [4, 89], - [4, 90], - [4, 91], - [4, 92], - [4, 93], - [4, 94], - [4, 95], - [4, 96], - [4, 97], - [4, 98], - [4, 99], - [4, 100], - [4, 101], - [4, 102], - [4, 103], - [4, 104], - [4, 105], - [4, 106], - [4, 107], - [4, 108], - [4, 109], - [4, 110], - [4, 111], - [4, 112], - [4, 113], - [4, 114], - [4, 115], - [4, 116], - [4, 117], - [4, 118], - [4, 119], - [4, 120], - [4, 121], - [4, 122], - [4, 123], - [4, 124], - [4, 125], - [4, 126], - [4, 127], - [4, 128], - [4, 129], - [4, 130], - [4, 131], - [4, 132], - [4, 133], - [4, 134], - [4, 135], - [4, 136], - [4, 137], - [4, 138], - [4, 139], - [4, 140], - [4, 141], - [4, 142], - [4, 143], - [4, 144], - [4, 145], - [4, 146], - [4, 147], - [4, 148], - [4, 149], - [4, 150], - [4, 151], - [4, 152], - [4, 153], - [4, 154], - [4, 155], - [4, 156], - [4, 157], - [4, 158], - [4, 159], - [4, 160], - [4, 161], - [4, 162], - [4, 163], - [4, 164], - [4, 165], - [4, 166], - [4, 167], - [4, 168], - [4, 169], - [4, 170], - [4, 171], - [4, 172], - [4, 173], - [4, 174], - [4, 175], - [4, 176], - [4, 177], - [4, 178], - [4, 179], - [4, 180], - [4, 181], - [4, 182], - [4, 183], - [4, 184], - [4, 185], - [4, 186], - [4, 187], - [4, 188], - [4, 189], - [4, 190], - [4, 191], - [4, 192], - [4, 193], - [4, 194], - [4, 195], - [4, 196], - [4, 197], - [4, 198], - [4, 199], - [4, 200], - [4, 201], - [4, 202], - [4, 203], - [4, 204], - [4, 205], - [4, 206], - [4, 207], - [4, 208], - [4, 209], - [4, 210], - [4, 211], - [4, 212], - [4, 213], - [4, 214], - [4, 215], - [4, 216], - [4, 217], - [4, 218], - [4, 219], - [4, 220], - [4, 221], - [4, 222], - [4, 223], - [4, 224], - [4, 225], - [4, 226], - [4, 227], - [4, 228], - [4, 229], - [4, 230], - [4, 231], - [4, 232], - [4, 233], - [4, 234], - [4, 235], - [4, 236], - [4, 237], - [4, 238], - [4, 239], - [4, 240], - [4, 241], - [4, 242], - [4, 243], - [4, 244], - [4, 245], - [4, 246], - [4, 247], - [4, 248], - [4, 249], - [4, 250], - [4, 251], - [4, 252], - [4, 253], - [4, 254], - [4, 255], - [4, 256], - [4, 257], - [4, 258], - [4, 259], - [4, 260], - [4, 261], - [4, 262], - [4, 263], - [4, 264], - [4, 265], - [4, 266], - [4, 267], - [4, 268], - [4, 269], - [4, 270], - [4, 271], - [4, 272], - [4, 273], - [4, 274], - [4, 275], - [4, 276], - [4, 277], - [4, 278], - [4, 279], - [4, 280], - [4, 281], - [4, 282], - [4, 283], - [4, 284], - [4, 285], - [4, 286], - [4, 287], - [4, 288], - [4, 289], - [4, 290], - [4, 291], - [4, 292], - [4, 293], - [4, 294], - [4, 295], - [4, 296], - [4, 297], - [4, 298], - [4, 299], - [4, 300], - [4, 301], - [4, 302], - [4, 303], - [4, 304], - [4, 305], - [4, 306], - [4, 307], - [4, 308], - [4, 309], - [4, 310], - [4, 311], - [4, 312], - [4, 313], - [4, 314], - [4, 315], - [4, 316], - [4, 317], - [4, 318], - [4, 319], - [4, 320], - [4, 321], - [4, 322], - [4, 323], - [4, 324], - [4, 325], - [4, 326], - [4, 327], - [4, 328], - [4, 329], - [4, 330], - [4, 331], - [4, 332], - [4, 333], - [4, 334], - [4, 335], - [4, 336], - [4, 337], - [4, 338], - [4, 339], - [4, 340], - [4, 341], - [4, 342], - [4, 343], - [4, 344], - [4, 345], - [4, 346], - [4, 347], - [4, 348], - [4, 349], - [4, 350], - [4, 351], - [4, 352], - [4, 353], - [4, 354], - [4, 355], - [4, 356], - [4, 357], - [4, 358], - [4, 359], - [4, 360], - [4, 361], - [4, 362], - [4, 363], - [4, 364], - [4, 365], - [4, 366], - [4, 367], - [4, 368], - [4, 369], - [4, 370], - [4, 371], - [4, 372], - [4, 373], - [4, 374], - [4, 375], - [4, 376], - [4, 377], - [4, 378], - [4, 379], - [4, 380], - [4, 381], - [4, 382], - [4, 383], - [4, 384], - [4, 385], - [4, 386], - [4, 387], - [4, 388], - [4, 389], - [4, 390], - [4, 391], - [4, 392], - [4, 393], - [4, 394], - [4, 395], - [4, 396], - [4, 397], - [4, 398], - [4, 399], - [4, 400], - [4, 401], - [4, 402], - [4, 403], - [4, 404], - [4, 405], - [4, 406], - [4, 407], - [4, 408], - [4, 409], - [4, 410], - [4, 411], - [4, 412], - [4, 413], - [4, 414], - [4, 415], - [4, 416], - [4, 417], - [4, 418], - [4, 419], - [4, 420], - [4, 421], - [4, 422], - [4, 423], - [4, 424], - [4, 425], - [4, 426], - [4, 427], - [4, 428], - [4, 429], - [4, 430], - [4, 431], - [4, 432], - [4, 433], - [4, 434], - [4, 435], - [4, 436], - [4, 437], - [4, 438], - [4, 439], - [4, 440], - [4, 441], - [4, 442], - [4, 443], - [4, 444], - [4, 445], - [4, 446], - [4, 447], - [4, 448], - [4, 449], - [4, 450], - [4, 451], - [4, 452], - [4, 453], - [4, 454], - [4, 455], - [4, 456], - [4, 457], - [4, 458], - [4, 459], - [4, 460], - [4, 461], - [4, 462], - [4, 463], - [4, 464], - [4, 465], - [4, 466], - [4, 467], - [4, 468], - [4, 469], - [4, 470], - [4, 471], - [4, 472], - [4, 473], - [4, 474], - [4, 475], - [4, 476], - [4, 477], - [4, 478], - [4, 479], - [4, 480], - [4, 481], - [4, 482], - [4, 483], - [4, 484], - [4, 485], - [4, 486], - [4, 487], - [4, 488], - [4, 489], - [4, 490], - [4, 491], - [4, 492], - [4, 493], - [4, 494], - [4, 495], - [4, 496], - [4, 497], - [4, 498], - [4, 499], - [4, 500], - [5, 2], - [5, 3], - [5, 4], - [5, 5], - [5, 6], - [5, 7], - [5, 8], - [5, 9], - [5, 10], - [5, 11], - [5, 12], - [5, 13], - [5, 14], - [5, 15], - [5, 16], - [5, 17], - [5, 18], - [5, 19], - [5, 20], - [5, 21], - [5, 22], - [5, 23], - [5, 24], - [5, 25], - [5, 26], - [5, 27], - [5, 28], - [5, 29], - [5, 30], - [5, 31], - [5, 32], - [5, 33], - [5, 34], - [5, 35], - [5, 36], - [5, 37], - [5, 38], - [5, 39], - [5, 40], - [5, 41], - [5, 42], - [5, 43], - [5, 44], - [5, 45], - [5, 46], - [5, 47], - [5, 48], - [5, 49], - [5, 50], - [5, 51], - [5, 52], - [5, 53], - [5, 54], - [5, 55], - [5, 56], - [5, 57], - [5, 58], - [5, 59], - [5, 60], - [5, 61], - [5, 62], - [5, 63], - [5, 64], - [5, 65], - [5, 66], - [5, 67], - [5, 68], - [5, 69], - [5, 70], - [5, 71], - [5, 72], - [5, 73], - [5, 74], - [5, 75], - [5, 76], - [5, 77], - [5, 78], - [5, 79], - [5, 80], - [5, 81], - [5, 82], - [5, 83], - [5, 84], - [5, 85], - [5, 86], - [5, 87], - [5, 88], - [5, 89], - [5, 90], - [5, 91], - [5, 92], - [5, 93], - [5, 94], - [5, 95], - [5, 96], - [5, 97], - [5, 98], - [5, 99], - [5, 100], - [5, 101], - [5, 102], - [5, 103], - [5, 104], - [5, 105], - [5, 106], - [5, 107], - [5, 108], - [5, 109], - [5, 110], - [5, 111], - [5, 112], - [5, 113], - [5, 114], - [5, 115], - [5, 116], - [5, 117], - [5, 118], - [5, 119], - [5, 120], - [5, 121], - [5, 122], - [5, 123], - [5, 124], - [5, 125], - [5, 126], - [5, 127], - [5, 128], - [5, 129], - [5, 130], - [5, 131], - [5, 132], - [5, 133], - [5, 134], - [5, 135], - [5, 136], - [5, 137], - [5, 138], - [5, 139], - [5, 140], - [5, 141], - [5, 142], - [5, 143], - [5, 144], - [5, 145], - [5, 146], - [5, 147], - [5, 148], - [5, 149], - [5, 150], - [5, 151], - [5, 152], - [5, 153], - [5, 154], - [5, 155], - [5, 156], - [5, 157], - [5, 158], - [5, 159], - [5, 160], - [5, 161], - [5, 162], - [5, 163], - [5, 164], - [5, 165], - [5, 166], - [5, 167], - [5, 168], - [5, 169], - [5, 170], - [5, 171], - [5, 172], - [5, 173], - [5, 174], - [5, 175], - [5, 176], - [5, 177], - [5, 178], - [5, 179], - [5, 180], - [5, 181], - [5, 182], - [5, 183], - [5, 184], - [5, 185], - [5, 186], - [5, 187], - [5, 188], - [5, 189], - [5, 190], - [5, 191], - [5, 192], - [5, 193], - [5, 194], - [5, 195], - [5, 196], - [5, 197], - [5, 198], - [5, 199], - [5, 200], - [5, 201], - [5, 202], - [5, 203], - [5, 204], - [5, 205], - [5, 206], - [5, 207], - [5, 208], - [5, 209], - [5, 210], - [5, 211], - [5, 212], - [5, 213], - [5, 214], - [5, 215], - [5, 216], - [5, 217], - [5, 218], - [5, 219], - [5, 220], - [5, 221], - [5, 222], - [5, 223], - [5, 224], - [5, 225], - [5, 226], - [5, 227], - [5, 228], - [5, 229], - [5, 230], - [5, 231], - [5, 232], - [5, 233], - [5, 234], - [5, 235], - [5, 236], - [5, 237], - [5, 238], - [5, 239], - [5, 240], - [5, 241], - [5, 242], - [5, 243], - [5, 244], - [5, 245], - [5, 246], - [5, 247], - [5, 248], - [5, 249], - [5, 250], - [5, 251], - [5, 252], - [5, 253], - [5, 254], - [5, 255], - [5, 256], - [5, 257], - [5, 258], - [5, 259], - [5, 260], - [5, 261], - [5, 262], - [5, 263], - [5, 264], - [5, 265], - [5, 266], - [5, 267], - [5, 268], - [5, 269], - [5, 270], - [5, 271], - [5, 272], - [5, 273], - [5, 274], - [5, 275], - [5, 276], - [5, 277], - [5, 278], - [5, 279], - [5, 280], - [5, 281], - [5, 282], - [5, 283], - [5, 284], - [5, 285], - [5, 286], - [5, 287], - [5, 288], - [5, 289], - [5, 290], - [5, 291], - [5, 292], - [5, 293], - [5, 294], - [5, 295], - [5, 296], - [5, 297], - [5, 298], - [5, 299], - [5, 300], - [5, 301], - [5, 302], - [5, 303], - [5, 304], - [5, 305], - [5, 306], - [5, 307], - [5, 308], - [5, 309], - [5, 310], - [5, 311], - [5, 312], - [5, 313], - [5, 314], - [5, 315], - [5, 316], - [5, 317], - [5, 318], - [5, 319], - [5, 320], - [5, 321], - [5, 322], - [5, 323], - [5, 324], - [5, 325], - [5, 326], - [5, 327], - [5, 328], - [5, 329], - [5, 330], - [5, 331], - [5, 332], - [5, 333], - [5, 334], - [5, 335], - [5, 336], - [5, 337], - [5, 338], - [5, 339], - [5, 340], - [5, 341], - [5, 342], - [5, 343], - [5, 344], - [5, 345], - [5, 346], - [5, 347], - [5, 348], - [5, 349], - [5, 350], - [5, 351], - [5, 352], - [5, 353], - [5, 354], - [5, 355], - [5, 356], - [5, 357], - [5, 358], - [5, 359], - [5, 360], - [5, 361], - [5, 362], - [5, 363], - [5, 364], - [5, 365], - [5, 366], - [5, 367], - [5, 368], - [5, 369], - [5, 370], - [5, 371], - [5, 372], - [5, 373], - [5, 374], - [5, 375], - [5, 376], - [5, 377], - [5, 378], - [5, 379], - [5, 380], - [5, 381], - [5, 382], - [5, 383], - [5, 384], - [5, 385], - [5, 386], - [5, 387], - [5, 388], - [5, 389], - [5, 390], - [5, 391], - [5, 392], - [5, 393], - [5, 394], - [5, 395], - [5, 396], - [5, 397], - [5, 398], - [5, 399], - [5, 400], - [5, 401], - [5, 402], - [5, 403], - [5, 404], - [5, 405], - [5, 406], - [5, 407], - [5, 408], - [5, 409], - [5, 410], - [5, 411], - [5, 412], - [5, 413], - [5, 414], - [5, 415], - [5, 416], - [5, 417], - [5, 418], - [5, 419], - [5, 420], - [5, 421], - [5, 422], - [5, 423], - [5, 424], - [5, 425], - [5, 426], - [5, 427], - [5, 428], - [5, 429], - [5, 430], - [5, 431], - [5, 432], - [5, 433], - [5, 434], - [5, 435], - [5, 436], - [5, 437], - [5, 438], - [5, 439], - [5, 440], - [5, 441], - [5, 442], - [5, 443], - [5, 444], - [5, 445], - [5, 446], - [5, 447], - [5, 448], - [5, 449], - [5, 450], - [5, 451], - [5, 452], - [5, 453], - [5, 454], - [5, 455], - [5, 456], - [5, 457], - [5, 458], - [5, 459], - [5, 460], - [5, 461], - [5, 462], - [5, 463], - [5, 464], - [5, 465], - [5, 466], - [5, 467], - [5, 468], - [5, 469], - [5, 470], - [5, 471], - [5, 472], - [5, 473], - [5, 474], - [5, 475], - [5, 476], - [5, 477], - [5, 478], - [5, 479], - [5, 480], - [5, 481], - [5, 482], - [5, 483], - [5, 484], - [5, 485], - [5, 486], - [5, 487], - [5, 488], - [5, 489], - [5, 490], - [5, 491], - [5, 492], - [5, 493], - [5, 494], - [5, 495], - [5, 496], - [5, 497], - [5, 498], - [5, 499], - [5, 500], - [6, 2], - [6, 3], - [6, 4], - [6, 5], - [6, 6], - [6, 7], - [6, 8], - [6, 9], - [6, 10], - [6, 11], - [6, 12], - [6, 13], - [6, 14], - [6, 15], - [6, 16], - [6, 17], - [6, 18], - [6, 19], - [6, 20], - [6, 21], - [6, 22], - [6, 23], - [6, 24], - [6, 25], - [6, 26], - [6, 27], - [6, 28], - [6, 29], - [6, 30], - [6, 31], - [6, 32], - [6, 33], - [6, 34], - [6, 35], - [6, 36], - [6, 37], - [6, 38], - [6, 39], - [6, 40], - [6, 41], - [6, 42], - [6, 43], - [6, 44], - [6, 45], - [6, 46], - [6, 47], - [6, 48], - [6, 49], - [6, 50], - [6, 51], - [6, 52], - [6, 53], - [6, 54], - [6, 55], - [6, 56], - [6, 57], - [6, 58], - [6, 59], - [6, 60], - [6, 61], - [6, 62], - [6, 63], - [6, 64], - [6, 65], - [6, 66], - [6, 67], - [6, 68], - [6, 69], - [6, 70], - [6, 71], - [6, 72], - [6, 73], - [6, 74], - [6, 75], - [6, 76], - [6, 77], - [6, 78], - [6, 79], - [6, 80], - [6, 81], - [6, 82], - [6, 83], - [6, 84], - [6, 85], - [6, 86], - [6, 87], - [6, 88], - [6, 89], - [6, 90], - [6, 91], - [6, 92], - [6, 93], - [6, 94], - [6, 95], - [6, 96], - [6, 97], - [6, 98], - [6, 99], - [6, 100], - [6, 101], - [6, 102], - [6, 103], - [6, 104], - [6, 105], - [6, 106], - [6, 107], - [6, 108], - [6, 109], - [6, 110], - [6, 111], - [6, 112], - [6, 113], - [6, 114], - [6, 115], - [6, 116], - [6, 117], - [6, 118], - [6, 119], - [6, 120], - [6, 121], - [6, 122], - [6, 123], - [6, 124], - [6, 125], - [6, 126], - [6, 127], - [6, 128], - [6, 129], - [6, 130], - [6, 131], - [6, 132], - [6, 133], - [6, 134], - [6, 135], - [6, 136], - [6, 137], - [6, 138], - [6, 139], - [6, 140], - [6, 141], - [6, 142], - [6, 143], - [6, 144], - [6, 145], - [6, 146], - [6, 147], - [6, 148], - [6, 149], - [6, 150], - [6, 151], - [6, 152], - [6, 153], - [6, 154], - [6, 155], - [6, 156], - [6, 157], - [6, 158], - [6, 159], - [6, 160], - [6, 161], - [6, 162], - [6, 163], - [6, 164], - [6, 165], - [6, 166], - [6, 167], - [6, 168], - [6, 169], - [6, 170], - [6, 171], - [6, 172], - [6, 173], - [6, 174], - [6, 175], - [6, 176], - [6, 177], - [6, 178], - [6, 179], - [6, 180], - [6, 181], - [6, 182], - [6, 183], - [6, 184], - [6, 185], - [6, 186], - [6, 187], - [6, 188], - [6, 189], - [6, 190], - [6, 191], - [6, 192], - [6, 193], - [6, 194], - [6, 195], - [6, 196], - [6, 197], - [6, 198], - [6, 199], - [6, 200], - [6, 201], - [6, 202], - [6, 203], - [6, 204], - [6, 205], - [6, 206], - [6, 207], - [6, 208], - [6, 209], - [6, 210], - [6, 211], - [6, 212], - [6, 213], - [6, 214], - [6, 215], - [6, 216], - [6, 217], - [6, 218], - [6, 219], - [6, 220], - [6, 221], - [6, 222], - [6, 223], - [6, 224], - [6, 225], - [6, 226], - [6, 227], - [6, 228], - [6, 229], - [6, 230], - [6, 231], - [6, 232], - [6, 233], - [6, 234], - [6, 235], - [6, 236], - [6, 237], - [6, 238], - [6, 239], - [6, 240], - [6, 241], - [6, 242], - [6, 243], - [6, 244], - [6, 245], - [6, 246], - [6, 247], - [6, 248], - [6, 249], - [6, 250], - [6, 251], - [6, 252], - [6, 253], - [6, 254], - [6, 255], - [6, 256], - [6, 257], - [6, 258], - [6, 259], - [6, 260], - [6, 261], - [6, 262], - [6, 263], - [6, 264], - [6, 265], - [6, 266], - [6, 267], - [6, 268], - [6, 269], - [6, 270], - [6, 271], - [6, 272], - [6, 273], - [6, 274], - [6, 275], - [6, 276], - [6, 277], - [6, 278], - [6, 279], - [6, 280], - [6, 281], - [6, 282], - [6, 283], - [6, 284], - [6, 285], - [6, 286], - [6, 287], - [6, 288], - [6, 289], - [6, 290], - [6, 291], - [6, 292], - [6, 293], - [6, 294], - [6, 295], - [6, 296], - [6, 297], - [6, 298], - [6, 299], - [6, 300], - [6, 301], - [6, 302], - [6, 303], - [6, 304], - [6, 305], - [6, 306], - [6, 307], - [6, 308], - [6, 309], - [6, 310], - [6, 311], - [6, 312], - [6, 313], - [6, 314], - [6, 315], - [6, 316], - [6, 317], - [6, 318], - [6, 319], - [6, 320], - [6, 321], - [6, 322], - [6, 323], - [6, 324], - [6, 325], - [6, 326], - [6, 327], - [6, 328], - [6, 329], - [6, 330], - [6, 331], - [6, 332], - [6, 333], - [6, 334], - [6, 335], - [6, 336], - [6, 337], - [6, 338], - [6, 339], - [6, 340], - [6, 341], - [6, 342], - [6, 343], - [6, 344], - [6, 345], - [6, 346], - [6, 347], - [6, 348], - [6, 349], - [6, 350], - [6, 351], - [6, 352], - [6, 353], - [6, 354], - [6, 355], - [6, 356], - [6, 357], - [6, 358], - [6, 359], - [6, 360], - [6, 361], - [6, 362], - [6, 363], - [6, 364], - [6, 365], - [6, 366], - [6, 367], - [6, 368], - [6, 369], - [6, 370], - [6, 371], - [6, 372], - [6, 373], - [6, 374], - [6, 375], - [6, 376], - [6, 377], - [6, 378], - [6, 379], - [6, 380], - [6, 381], - [6, 382], - [6, 383], - [6, 384], - [6, 385], - [6, 386], - [6, 387], - [6, 388], - [6, 389], - [6, 390], - [6, 391], - [6, 392], - [6, 393], - [6, 394], - [6, 395], - [6, 396], - [6, 397], - [6, 398], - [6, 399], - [6, 400], - [6, 401], - [6, 402], - [6, 403], - [6, 404], - [6, 405], - [6, 406], - [6, 407], - [6, 408], - [6, 409], - [6, 410], - [6, 411], - [6, 412], - [6, 413], - [6, 414], - [6, 415], - [6, 416], - [6, 417], - [6, 418], - [6, 419], - [6, 420], - [6, 421], - [6, 422], - [6, 423], - [6, 424], - [6, 425], - [6, 426], - [6, 427], - [6, 428], - [6, 429], - [6, 430], - [6, 431], - [6, 432], - [6, 433], - [6, 434], - [6, 435], - [6, 436], - [6, 437], - [6, 438], - [6, 439], - [6, 440], - [6, 441], - [6, 442], - [6, 443], - [6, 444], - [6, 445], - [6, 446], - [6, 447], - [6, 448], - [6, 449], - [6, 450], - [6, 451], - [6, 452], - [6, 453], - [6, 454], - [6, 455], - [6, 456], - [6, 457], - [6, 458], - [6, 459], - [6, 460], - [6, 461], - [6, 462], - [6, 463], - [6, 464], - [6, 465], - [6, 466], - [6, 467], - [6, 468], - [6, 469], - [6, 470], - [6, 471], - [6, 472], - [6, 473], - [6, 474], - [6, 475], - [6, 476], - [6, 477], - [6, 478], - [6, 479], - [6, 480], - [6, 481], - [6, 482], - [6, 483], - [6, 484], - [6, 485], - [6, 486], - [6, 487], - [6, 488], - [6, 489], - [6, 490], - [6, 491], - [6, 492], - [6, 493], - [6, 494], - [6, 495], - [6, 496], - [6, 497], - [6, 498], - [6, 499], - [6, 500], - [7, 2], - [7, 3], - [7, 4], - [7, 5], - [7, 6], - [7, 7], - [7, 8], - [7, 9], - [7, 10], - [7, 11], - [7, 12], - [7, 13], - [7, 14], - [7, 15], - [7, 16], - [7, 17], - [7, 18], - [7, 19], - [7, 20], - [7, 21], - [7, 22], - [7, 23], - [7, 24], - [7, 25], - [7, 26], - [7, 27], - [7, 28], - [7, 29], - [7, 30], - [7, 31], - [7, 32], - [7, 33], - [7, 34], - [7, 35], - [7, 36], - [7, 37], - [7, 38], - [7, 39], - [7, 40], - [7, 41], - [7, 42], - [7, 43], - [7, 44], - [7, 45], - [7, 46], - [7, 47], - [7, 48], - [7, 49], - [7, 50], - [7, 51], - [7, 52], - [7, 53], - [7, 54], - [7, 55], - [7, 56], - [7, 57], - [7, 58], - [7, 59], - [7, 60], - [7, 61], - [7, 62], - [7, 63], - [7, 64], - [7, 65], - [7, 66], - [7, 67], - [7, 68], - [7, 69], - [7, 70], - [7, 71], - [7, 72], - [7, 73], - [7, 74], - [7, 75], - [7, 76], - [7, 77], - [7, 78], - [7, 79], - [7, 80], - [7, 81], - [7, 82], - [7, 83], - [7, 84], - [7, 85], - [7, 86], - [7, 87], - [7, 88], - [7, 89], - [7, 90], - [7, 91], - [7, 92], - [7, 93], - [7, 94], - [7, 95], - [7, 96], - [7, 97], - [7, 98], - [7, 99], - [7, 100], - [7, 101], - [7, 102], - [7, 103], - [7, 104], - [7, 105], - [7, 106], - [7, 107], - [7, 108], - [7, 109], - [7, 110], - [7, 111], - [7, 112], - [7, 113], - [7, 114], - [7, 115], - [7, 116], - [7, 117], - [7, 118], - [7, 119], - [7, 120], - [7, 121], - [7, 122], - [7, 123], - [7, 124], - [7, 125], - [7, 126], - [7, 127], - [7, 128], - [7, 129], - [7, 130], - [7, 131], - [7, 132], - [7, 133], - [7, 134], - [7, 135], - [7, 136], - [7, 137], - [7, 138], - [7, 139], - [7, 140], - [7, 141], - [7, 142], - [7, 143], - [7, 144], - [7, 145], - [7, 146], - [7, 147], - [7, 148], - [7, 149], - [7, 150], - [7, 151], - [7, 152], - [7, 153], - [7, 154], - [7, 155], - [7, 156], - [7, 157], - [7, 158], - [7, 159], - [7, 160], - [7, 161], - [7, 162], - [7, 163], - [7, 164], - [7, 165], - [7, 166], - [7, 167], - [7, 168], - [7, 169], - [7, 170], - [7, 171], - [7, 172], - [7, 173], - [7, 174], - [7, 175], - [7, 176], - [7, 177], - [7, 178], - [7, 179], - [7, 180], - [7, 181], - [7, 182], - [7, 183], - [7, 184], - [7, 185], - [7, 186], - [7, 187], - [7, 188], - [7, 189], - [7, 190], - [7, 191], - [7, 192], - [7, 193], - [7, 194], - [7, 195], - [7, 196], - [7, 197], - [7, 198], - [7, 199], - [7, 200], - [7, 201], - [7, 202], - [7, 203], - [7, 204], - [7, 205], - [7, 206], - [7, 207], - [7, 208], - [7, 209], - [7, 210], - [7, 211], - [7, 212], - [7, 213], - [7, 214], - [7, 215], - [7, 216], - [7, 217], - [7, 218], - [7, 219], - [7, 220], - [7, 221], - [7, 222], - [7, 223], - [7, 224], - [7, 225], - [7, 226], - [7, 227], - [7, 228], - [7, 229], - [7, 230], - [7, 231], - [7, 232], - [7, 233], - [7, 234], - [7, 235], - [7, 236], - [7, 237], - [7, 238], - [7, 239], - [7, 240], - [7, 241], - [7, 242], - [7, 243], - [7, 244], - [7, 245], - [7, 246], - [7, 247], - [7, 248], - [7, 249], - [7, 250], - [7, 251], - [7, 252], - [7, 253], - [7, 254], - [7, 255], - [7, 256], - [7, 257], - [7, 258], - [7, 259], - [7, 260], - [7, 261], - [7, 262], - [7, 263], - [7, 264], - [7, 265], - [7, 266], - [7, 267], - [7, 268], - [7, 269], - [7, 270], - [7, 271], - [7, 272], - [7, 273], - [7, 274], - [7, 275], - [7, 276], - [7, 277], - [7, 278], - [7, 279], - [7, 280], - [7, 281], - [7, 282], - [7, 283], - [7, 284], - [7, 285], - [7, 286], - [7, 287], - [7, 288], - [7, 289], - [7, 290], - [7, 291], - [7, 292], - [7, 293], - [7, 294], - [7, 295], - [7, 296], - [7, 297], - [7, 298], - [7, 299], - [7, 300], - [7, 301], - [7, 302], - [7, 303], - [7, 304], - [7, 305], - [7, 306], - [7, 307], - [7, 308], - [7, 309], - [7, 310], - [7, 311], - [7, 312], - [7, 313], - [7, 314], - [7, 315], - [7, 316], - [7, 317], - [7, 318], - [7, 319], - [7, 320], - [7, 321], - [7, 322], - [7, 323], - [7, 324], - [7, 325], - [7, 326], - [7, 327], - [7, 328], - [7, 329], - [7, 330], - [7, 331], - [7, 332], - [7, 333], - [7, 334], - [7, 335], - [7, 336], - [7, 337], - [7, 338], - [7, 339], - [7, 340], - [7, 341], - [7, 342], - [7, 343], - [7, 344], - [7, 345], - [7, 346], - [7, 347], - [7, 348], - [7, 349], - [7, 350], - [7, 351], - [7, 352], - [7, 353], - [7, 354], - [7, 355], - [7, 356], - [7, 357], - [7, 358], - [7, 359], - [7, 360], - [7, 361], - [7, 362], - [7, 363], - [7, 364], - [7, 365], - [7, 366], - [7, 367], - [7, 368], - [7, 369], - [7, 370], - [7, 371], - [7, 372], - [7, 373], - [7, 374], - [7, 375], - [7, 376], - [7, 377], - [7, 378], - [7, 379], - [7, 380], - [7, 381], - [7, 382], - [7, 383], - [7, 384], - [7, 385], - [7, 386], - [7, 387], - [7, 388], - [7, 389], - [7, 390], - [7, 391], - [7, 392], - [7, 393], - [7, 394], - [7, 395], - [7, 396], - [7, 397], - [7, 398], - [7, 399], - [7, 400], - [7, 401], - [7, 402], - [7, 403], - [7, 404], - [7, 405], - [7, 406], - [7, 407], - [7, 408], - [7, 409], - [7, 410], - [7, 411], - [7, 412], - [7, 413], - [7, 414], - [7, 415], - [7, 416], - [7, 417], - [7, 418], - [7, 419], - [7, 420], - [7, 421], - [7, 422], - [7, 423], - [7, 424], - [7, 425], - [7, 426], - [7, 427], - [7, 428], - [7, 429], - [7, 430], - [7, 431], - [7, 432], - [7, 433], - [7, 434], - [7, 435], - [7, 436], - [7, 437], - [7, 438], - [7, 439], - [7, 440], - [7, 441], - [7, 442], - [7, 443], - [7, 444], - [7, 445], - [7, 446], - [7, 447], - [7, 448], - [7, 449], - [7, 450], - [7, 451], - [7, 452], - [7, 453], - [7, 454], - [7, 455], - [7, 456], - [7, 457], - [7, 458], - [7, 459], - [7, 460], - [7, 461], - [7, 462], - [7, 463], - [7, 464], - [7, 465], - [7, 466], - [7, 467], - [7, 468], - [7, 469], - [7, 470], - [7, 471], - [7, 472], - [7, 473], - [7, 474], - [7, 475], - [7, 476], - [7, 477], - [7, 478], - [7, 479], - [7, 480], - [7, 481], - [7, 482], - [7, 483], - [7, 484], - [7, 485], - [7, 486], - [7, 487], - [7, 488], - [7, 489], - [7, 490], - [7, 491], - [7, 492], - [7, 493], - [7, 494], - [7, 495], - [7, 496], - [7, 497], - [7, 498], - [7, 499], - [7, 500], - [21, 3] - ] - }, - { - "x": 13, - "y": 3, - "type": "COMPUTED", - "value": "00V", - "last_modified": "2023-02-17T00:03:23.613Z" - }, - { - "x": 14, - "y": 3, - "type": "COMPUTED", - "value": "Meadow Lake", - "last_modified": "2023-02-17T00:03:23.613Z" - }, - { - "x": 15, - "y": 3, - "type": "COMPUTED", - "value": "Colorado Springs", - "last_modified": "2023-02-17T00:03:23.613Z" - }, - { - "x": 16, - "y": 3, - "type": "COMPUTED", - "value": "CO", - "last_modified": "2023-02-17T00:03:23.613Z" - }, - { - "x": 17, - "y": 3, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:23.613Z" - }, - { - "x": 18, - "y": 3, - "type": "COMPUTED", - "value": "38.94574889", - "last_modified": "2023-02-17T00:03:23.613Z" - }, - { - "x": 19, - "y": 3, - "type": "COMPUTED", - "value": "-104.5698933", - "last_modified": "2023-02-17T00:03:23.613Z" - }, - { - "x": 10, - "y": 4, - "type": "TEXT", - "value": "Airport 2", - "last_modified": "2023-02-16T23:50:50.037Z" - }, - { - "x": 12, - "y": 4, - "type": "PYTHON", - "value": "33", - "python_code": "df = getCells((0, 2), (7, 503), first_row_header=True)\ndf = df[df[\"iata\"] == c(11, 4)].head(1)\ndf = df.fillna('')\ndf.columns = range(df.columns.size)\ndf\n", - "python_output": "", - "array_cells": [ - [12, 4], - [13, 4], - [14, 4], - [15, 4], - [16, 4], - [17, 4], - [18, 4], - [19, 4] - ], - "last_modified": "2023-02-17T00:03:28.164Z", - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": " 0 1 2 ... 5 6 7\n33 33 09W South Capitol Street ... USA 38.86872333 -77.00747583\n\n[1 rows x 8 columns]", - "cells_accessed": [ - [0, 2], - [0, 3], - [0, 4], - [0, 5], - [0, 6], - [0, 7], - [0, 8], - [0, 9], - [0, 10], - [0, 11], - [0, 12], - [0, 13], - [0, 14], - [0, 15], - [0, 16], - [0, 17], - [0, 18], - [0, 19], - [0, 20], - [0, 21], - [0, 22], - [0, 23], - [0, 24], - [0, 25], - [0, 26], - [0, 27], - [0, 28], - [0, 29], - [0, 30], - [0, 31], - [0, 32], - [0, 33], - [0, 34], - [0, 35], - [0, 36], - [0, 37], - [0, 38], - [0, 39], - [0, 40], - [0, 41], - [0, 42], - [0, 43], - [0, 44], - [0, 45], - [0, 46], - [0, 47], - [0, 48], - [0, 49], - [0, 50], - [0, 51], - [0, 52], - [0, 53], - [0, 54], - [0, 55], - [0, 56], - [0, 57], - [0, 58], - [0, 59], - [0, 60], - [0, 61], - [0, 62], - [0, 63], - [0, 64], - [0, 65], - [0, 66], - [0, 67], - [0, 68], - [0, 69], - [0, 70], - [0, 71], - [0, 72], - [0, 73], - [0, 74], - [0, 75], - [0, 76], - [0, 77], - [0, 78], - [0, 79], - [0, 80], - [0, 81], - [0, 82], - [0, 83], - [0, 84], - [0, 85], - [0, 86], - [0, 87], - [0, 88], - [0, 89], - [0, 90], - [0, 91], - [0, 92], - [0, 93], - [0, 94], - [0, 95], - [0, 96], - [0, 97], - [0, 98], - [0, 99], - [0, 100], - [0, 101], - [0, 102], - [0, 103], - [0, 104], - [0, 105], - [0, 106], - [0, 107], - [0, 108], - [0, 109], - [0, 110], - [0, 111], - [0, 112], - [0, 113], - [0, 114], - [0, 115], - [0, 116], - [0, 117], - [0, 118], - [0, 119], - [0, 120], - [0, 121], - [0, 122], - [0, 123], - [0, 124], - [0, 125], - [0, 126], - [0, 127], - [0, 128], - [0, 129], - [0, 130], - [0, 131], - [0, 132], - [0, 133], - [0, 134], - [0, 135], - [0, 136], - [0, 137], - [0, 138], - [0, 139], - [0, 140], - [0, 141], - [0, 142], - [0, 143], - [0, 144], - [0, 145], - [0, 146], - [0, 147], - [0, 148], - [0, 149], - [0, 150], - [0, 151], - [0, 152], - [0, 153], - [0, 154], - [0, 155], - [0, 156], - [0, 157], - [0, 158], - [0, 159], - [0, 160], - [0, 161], - [0, 162], - [0, 163], - [0, 164], - [0, 165], - [0, 166], - [0, 167], - [0, 168], - [0, 169], - [0, 170], - [0, 171], - [0, 172], - [0, 173], - [0, 174], - [0, 175], - [0, 176], - [0, 177], - [0, 178], - [0, 179], - [0, 180], - [0, 181], - [0, 182], - [0, 183], - [0, 184], - [0, 185], - [0, 186], - [0, 187], - [0, 188], - [0, 189], - [0, 190], - [0, 191], - [0, 192], - [0, 193], - [0, 194], - [0, 195], - [0, 196], - [0, 197], - [0, 198], - [0, 199], - [0, 200], - [0, 201], - [0, 202], - [0, 203], - [0, 204], - [0, 205], - [0, 206], - [0, 207], - [0, 208], - [0, 209], - [0, 210], - [0, 211], - [0, 212], - [0, 213], - [0, 214], - [0, 215], - [0, 216], - [0, 217], - [0, 218], - [0, 219], - [0, 220], - [0, 221], - [0, 222], - [0, 223], - [0, 224], - [0, 225], - [0, 226], - [0, 227], - [0, 228], - [0, 229], - [0, 230], - [0, 231], - [0, 232], - [0, 233], - [0, 234], - [0, 235], - [0, 236], - [0, 237], - [0, 238], - [0, 239], - [0, 240], - [0, 241], - [0, 242], - [0, 243], - [0, 244], - [0, 245], - [0, 246], - [0, 247], - [0, 248], - [0, 249], - [0, 250], - [0, 251], - [0, 252], - [0, 253], - [0, 254], - [0, 255], - [0, 256], - [0, 257], - [0, 258], - [0, 259], - [0, 260], - [0, 261], - [0, 262], - [0, 263], - [0, 264], - [0, 265], - [0, 266], - [0, 267], - [0, 268], - [0, 269], - [0, 270], - [0, 271], - [0, 272], - [0, 273], - [0, 274], - [0, 275], - [0, 276], - [0, 277], - [0, 278], - [0, 279], - [0, 280], - [0, 281], - [0, 282], - [0, 283], - [0, 284], - [0, 285], - [0, 286], - [0, 287], - [0, 288], - [0, 289], - [0, 290], - [0, 291], - [0, 292], - [0, 293], - [0, 294], - [0, 295], - [0, 296], - [0, 297], - [0, 298], - [0, 299], - [0, 300], - [0, 301], - [0, 302], - [0, 303], - [0, 304], - [0, 305], - [0, 306], - [0, 307], - [0, 308], - [0, 309], - [0, 310], - [0, 311], - [0, 312], - [0, 313], - [0, 314], - [0, 315], - [0, 316], - [0, 317], - [0, 318], - [0, 319], - [0, 320], - [0, 321], - [0, 322], - [0, 323], - [0, 324], - [0, 325], - [0, 326], - [0, 327], - [0, 328], - [0, 329], - [0, 330], - [0, 331], - [0, 332], - [0, 333], - [0, 334], - [0, 335], - [0, 336], - [0, 337], - [0, 338], - [0, 339], - [0, 340], - [0, 341], - [0, 342], - [0, 343], - [0, 344], - [0, 345], - [0, 346], - [0, 347], - [0, 348], - [0, 349], - [0, 350], - [0, 351], - [0, 352], - [0, 353], - [0, 354], - [0, 355], - [0, 356], - [0, 357], - [0, 358], - [0, 359], - [0, 360], - [0, 361], - [0, 362], - [0, 363], - [0, 364], - [0, 365], - [0, 366], - [0, 367], - [0, 368], - [0, 369], - [0, 370], - [0, 371], - [0, 372], - [0, 373], - [0, 374], - [0, 375], - [0, 376], - [0, 377], - [0, 378], - [0, 379], - [0, 380], - [0, 381], - [0, 382], - [0, 383], - [0, 384], - [0, 385], - [0, 386], - [0, 387], - [0, 388], - [0, 389], - [0, 390], - [0, 391], - [0, 392], - [0, 393], - [0, 394], - [0, 395], - [0, 396], - [0, 397], - [0, 398], - [0, 399], - [0, 400], - [0, 401], - [0, 402], - [0, 403], - [0, 404], - [0, 405], - [0, 406], - [0, 407], - [0, 408], - [0, 409], - [0, 410], - [0, 411], - [0, 412], - [0, 413], - [0, 414], - [0, 415], - [0, 416], - [0, 417], - [0, 418], - [0, 419], - [0, 420], - [0, 421], - [0, 422], - [0, 423], - [0, 424], - [0, 425], - [0, 426], - [0, 427], - [0, 428], - [0, 429], - [0, 430], - [0, 431], - [0, 432], - [0, 433], - [0, 434], - [0, 435], - [0, 436], - [0, 437], - [0, 438], - [0, 439], - [0, 440], - [0, 441], - [0, 442], - [0, 443], - [0, 444], - [0, 445], - [0, 446], - [0, 447], - [0, 448], - [0, 449], - [0, 450], - [0, 451], - [0, 452], - [0, 453], - [0, 454], - [0, 455], - [0, 456], - [0, 457], - [0, 458], - [0, 459], - [0, 460], - [0, 461], - [0, 462], - [0, 463], - [0, 464], - [0, 465], - [0, 466], - [0, 467], - [0, 468], - [0, 469], - [0, 470], - [0, 471], - [0, 472], - [0, 473], - [0, 474], - [0, 475], - [0, 476], - [0, 477], - [0, 478], - [0, 479], - [0, 480], - [0, 481], - [0, 482], - [0, 483], - [0, 484], - [0, 485], - [0, 486], - [0, 487], - [0, 488], - [0, 489], - [0, 490], - [0, 491], - [0, 492], - [0, 493], - [0, 494], - [0, 495], - [0, 496], - [0, 497], - [0, 498], - [0, 499], - [0, 500], - [0, 501], - [0, 502], - [0, 503], - [1, 2], - [1, 3], - [1, 4], - [1, 5], - [1, 6], - [1, 7], - [1, 8], - [1, 9], - [1, 10], - [1, 11], - [1, 12], - [1, 13], - [1, 14], - [1, 15], - [1, 16], - [1, 17], - [1, 18], - [1, 19], - [1, 20], - [1, 21], - [1, 22], - [1, 23], - [1, 24], - [1, 25], - [1, 26], - [1, 27], - [1, 28], - [1, 29], - [1, 30], - [1, 31], - [1, 32], - [1, 33], - [1, 34], - [1, 35], - [1, 36], - [1, 37], - [1, 38], - [1, 39], - [1, 40], - [1, 41], - [1, 42], - [1, 43], - [1, 44], - [1, 45], - [1, 46], - [1, 47], - [1, 48], - [1, 49], - [1, 50], - [1, 51], - [1, 52], - [1, 53], - [1, 54], - [1, 55], - [1, 56], - [1, 57], - [1, 58], - [1, 59], - [1, 60], - [1, 61], - [1, 62], - [1, 63], - [1, 64], - [1, 65], - [1, 66], - [1, 67], - [1, 68], - [1, 69], - [1, 70], - [1, 71], - [1, 72], - [1, 73], - [1, 74], - [1, 75], - [1, 76], - [1, 77], - [1, 78], - [1, 79], - [1, 80], - [1, 81], - [1, 82], - [1, 83], - [1, 84], - [1, 85], - [1, 86], - [1, 87], - [1, 88], - [1, 89], - [1, 90], - [1, 91], - [1, 92], - [1, 93], - [1, 94], - [1, 95], - [1, 96], - [1, 97], - [1, 98], - [1, 99], - [1, 100], - [1, 101], - [1, 102], - [1, 103], - [1, 104], - [1, 105], - [1, 106], - [1, 107], - [1, 108], - [1, 109], - [1, 110], - [1, 111], - [1, 112], - [1, 113], - [1, 114], - [1, 115], - [1, 116], - [1, 117], - [1, 118], - [1, 119], - [1, 120], - [1, 121], - [1, 122], - [1, 123], - [1, 124], - [1, 125], - [1, 126], - [1, 127], - [1, 128], - [1, 129], - [1, 130], - [1, 131], - [1, 132], - [1, 133], - [1, 134], - [1, 135], - [1, 136], - [1, 137], - [1, 138], - [1, 139], - [1, 140], - [1, 141], - [1, 142], - [1, 143], - [1, 144], - [1, 145], - [1, 146], - [1, 147], - [1, 148], - [1, 149], - [1, 150], - [1, 151], - [1, 152], - [1, 153], - [1, 154], - [1, 155], - [1, 156], - [1, 157], - [1, 158], - [1, 159], - [1, 160], - [1, 161], - [1, 162], - [1, 163], - [1, 164], - [1, 165], - [1, 166], - [1, 167], - [1, 168], - [1, 169], - [1, 170], - [1, 171], - [1, 172], - [1, 173], - [1, 174], - [1, 175], - [1, 176], - [1, 177], - [1, 178], - [1, 179], - [1, 180], - [1, 181], - [1, 182], - [1, 183], - [1, 184], - [1, 185], - [1, 186], - [1, 187], - [1, 188], - [1, 189], - [1, 190], - [1, 191], - [1, 192], - [1, 193], - [1, 194], - [1, 195], - [1, 196], - [1, 197], - [1, 198], - [1, 199], - [1, 200], - [1, 201], - [1, 202], - [1, 203], - [1, 204], - [1, 205], - [1, 206], - [1, 207], - [1, 208], - [1, 209], - [1, 210], - [1, 211], - [1, 212], - [1, 213], - [1, 214], - [1, 215], - [1, 216], - [1, 217], - [1, 218], - [1, 219], - [1, 220], - [1, 221], - [1, 222], - [1, 223], - [1, 224], - [1, 225], - [1, 226], - [1, 227], - [1, 228], - [1, 229], - [1, 230], - [1, 231], - [1, 232], - [1, 233], - [1, 234], - [1, 235], - [1, 236], - [1, 237], - [1, 238], - [1, 239], - [1, 240], - [1, 241], - [1, 242], - [1, 243], - [1, 244], - [1, 245], - [1, 246], - [1, 247], - [1, 248], - [1, 249], - [1, 250], - [1, 251], - [1, 252], - [1, 253], - [1, 254], - [1, 255], - [1, 256], - [1, 257], - [1, 258], - [1, 259], - [1, 260], - [1, 261], - [1, 262], - [1, 263], - [1, 264], - [1, 265], - [1, 266], - [1, 267], - [1, 268], - [1, 269], - [1, 270], - [1, 271], - [1, 272], - [1, 273], - [1, 274], - [1, 275], - [1, 276], - [1, 277], - [1, 278], - [1, 279], - [1, 280], - [1, 281], - [1, 282], - [1, 283], - [1, 284], - [1, 285], - [1, 286], - [1, 287], - [1, 288], - [1, 289], - [1, 290], - [1, 291], - [1, 292], - [1, 293], - [1, 294], - [1, 295], - [1, 296], - [1, 297], - [1, 298], - [1, 299], - [1, 300], - [1, 301], - [1, 302], - [1, 303], - [1, 304], - [1, 305], - [1, 306], - [1, 307], - [1, 308], - [1, 309], - [1, 310], - [1, 311], - [1, 312], - [1, 313], - [1, 314], - [1, 315], - [1, 316], - [1, 317], - [1, 318], - [1, 319], - [1, 320], - [1, 321], - [1, 322], - [1, 323], - [1, 324], - [1, 325], - [1, 326], - [1, 327], - [1, 328], - [1, 329], - [1, 330], - [1, 331], - [1, 332], - [1, 333], - [1, 334], - [1, 335], - [1, 336], - [1, 337], - [1, 338], - [1, 339], - [1, 340], - [1, 341], - [1, 342], - [1, 343], - [1, 344], - [1, 345], - [1, 346], - [1, 347], - [1, 348], - [1, 349], - [1, 350], - [1, 351], - [1, 352], - [1, 353], - [1, 354], - [1, 355], - [1, 356], - [1, 357], - [1, 358], - [1, 359], - [1, 360], - [1, 361], - [1, 362], - [1, 363], - [1, 364], - [1, 365], - [1, 366], - [1, 367], - [1, 368], - [1, 369], - [1, 370], - [1, 371], - [1, 372], - [1, 373], - [1, 374], - [1, 375], - [1, 376], - [1, 377], - [1, 378], - [1, 379], - [1, 380], - [1, 381], - [1, 382], - [1, 383], - [1, 384], - [1, 385], - [1, 386], - [1, 387], - [1, 388], - [1, 389], - [1, 390], - [1, 391], - [1, 392], - [1, 393], - [1, 394], - [1, 395], - [1, 396], - [1, 397], - [1, 398], - [1, 399], - [1, 400], - [1, 401], - [1, 402], - [1, 403], - [1, 404], - [1, 405], - [1, 406], - [1, 407], - [1, 408], - [1, 409], - [1, 410], - [1, 411], - [1, 412], - [1, 413], - [1, 414], - [1, 415], - [1, 416], - [1, 417], - [1, 418], - [1, 419], - [1, 420], - [1, 421], - [1, 422], - [1, 423], - [1, 424], - [1, 425], - [1, 426], - [1, 427], - [1, 428], - [1, 429], - [1, 430], - [1, 431], - [1, 432], - [1, 433], - [1, 434], - [1, 435], - [1, 436], - [1, 437], - [1, 438], - [1, 439], - [1, 440], - [1, 441], - [1, 442], - [1, 443], - [1, 444], - [1, 445], - [1, 446], - [1, 447], - [1, 448], - [1, 449], - [1, 450], - [1, 451], - [1, 452], - [1, 453], - [1, 454], - [1, 455], - [1, 456], - [1, 457], - [1, 458], - [1, 459], - [1, 460], - [1, 461], - [1, 462], - [1, 463], - [1, 464], - [1, 465], - [1, 466], - [1, 467], - [1, 468], - [1, 469], - [1, 470], - [1, 471], - [1, 472], - [1, 473], - [1, 474], - [1, 475], - [1, 476], - [1, 477], - [1, 478], - [1, 479], - [1, 480], - [1, 481], - [1, 482], - [1, 483], - [1, 484], - [1, 485], - [1, 486], - [1, 487], - [1, 488], - [1, 489], - [1, 490], - [1, 491], - [1, 492], - [1, 493], - [1, 494], - [1, 495], - [1, 496], - [1, 497], - [1, 498], - [1, 499], - [1, 500], - [1, 501], - [1, 502], - [1, 503], - [2, 2], - [2, 3], - [2, 4], - [2, 5], - [2, 6], - [2, 7], - [2, 8], - [2, 9], - [2, 10], - [2, 11], - [2, 12], - [2, 13], - [2, 14], - [2, 15], - [2, 16], - [2, 17], - [2, 18], - [2, 19], - [2, 20], - [2, 21], - [2, 22], - [2, 23], - [2, 24], - [2, 25], - [2, 26], - [2, 27], - [2, 28], - [2, 29], - [2, 30], - [2, 31], - [2, 32], - [2, 33], - [2, 34], - [2, 35], - [2, 36], - [2, 37], - [2, 38], - [2, 39], - [2, 40], - [2, 41], - [2, 42], - [2, 43], - [2, 44], - [2, 45], - [2, 46], - [2, 47], - [2, 48], - [2, 49], - [2, 50], - [2, 51], - [2, 52], - [2, 53], - [2, 54], - [2, 55], - [2, 56], - [2, 57], - [2, 58], - [2, 59], - [2, 60], - [2, 61], - [2, 62], - [2, 63], - [2, 64], - [2, 65], - [2, 66], - [2, 67], - [2, 68], - [2, 69], - [2, 70], - [2, 71], - [2, 72], - [2, 73], - [2, 74], - [2, 75], - [2, 76], - [2, 77], - [2, 78], - [2, 79], - [2, 80], - [2, 81], - [2, 82], - [2, 83], - [2, 84], - [2, 85], - [2, 86], - [2, 87], - [2, 88], - [2, 89], - [2, 90], - [2, 91], - [2, 92], - [2, 93], - [2, 94], - [2, 95], - [2, 96], - [2, 97], - [2, 98], - [2, 99], - [2, 100], - [2, 101], - [2, 102], - [2, 103], - [2, 104], - [2, 105], - [2, 106], - [2, 107], - [2, 108], - [2, 109], - [2, 110], - [2, 111], - [2, 112], - [2, 113], - [2, 114], - [2, 115], - [2, 116], - [2, 117], - [2, 118], - [2, 119], - [2, 120], - [2, 121], - [2, 122], - [2, 123], - [2, 124], - [2, 125], - [2, 126], - [2, 127], - [2, 128], - [2, 129], - [2, 130], - [2, 131], - [2, 132], - [2, 133], - [2, 134], - [2, 135], - [2, 136], - [2, 137], - [2, 138], - [2, 139], - [2, 140], - [2, 141], - [2, 142], - [2, 143], - [2, 144], - [2, 145], - [2, 146], - [2, 147], - [2, 148], - [2, 149], - [2, 150], - [2, 151], - [2, 152], - [2, 153], - [2, 154], - [2, 155], - [2, 156], - [2, 157], - [2, 158], - [2, 159], - [2, 160], - [2, 161], - [2, 162], - [2, 163], - [2, 164], - [2, 165], - [2, 166], - [2, 167], - [2, 168], - [2, 169], - [2, 170], - [2, 171], - [2, 172], - [2, 173], - [2, 174], - [2, 175], - [2, 176], - [2, 177], - [2, 178], - [2, 179], - [2, 180], - [2, 181], - [2, 182], - [2, 183], - [2, 184], - [2, 185], - [2, 186], - [2, 187], - [2, 188], - [2, 189], - [2, 190], - [2, 191], - [2, 192], - [2, 193], - [2, 194], - [2, 195], - [2, 196], - [2, 197], - [2, 198], - [2, 199], - [2, 200], - [2, 201], - [2, 202], - [2, 203], - [2, 204], - [2, 205], - [2, 206], - [2, 207], - [2, 208], - [2, 209], - [2, 210], - [2, 211], - [2, 212], - [2, 213], - [2, 214], - [2, 215], - [2, 216], - [2, 217], - [2, 218], - [2, 219], - [2, 220], - [2, 221], - [2, 222], - [2, 223], - [2, 224], - [2, 225], - [2, 226], - [2, 227], - [2, 228], - [2, 229], - [2, 230], - [2, 231], - [2, 232], - [2, 233], - [2, 234], - [2, 235], - [2, 236], - [2, 237], - [2, 238], - [2, 239], - [2, 240], - [2, 241], - [2, 242], - [2, 243], - [2, 244], - [2, 245], - [2, 246], - [2, 247], - [2, 248], - [2, 249], - [2, 250], - [2, 251], - [2, 252], - [2, 253], - [2, 254], - [2, 255], - [2, 256], - [2, 257], - [2, 258], - [2, 259], - [2, 260], - [2, 261], - [2, 262], - [2, 263], - [2, 264], - [2, 265], - [2, 266], - [2, 267], - [2, 268], - [2, 269], - [2, 270], - [2, 271], - [2, 272], - [2, 273], - [2, 274], - [2, 275], - [2, 276], - [2, 277], - [2, 278], - [2, 279], - [2, 280], - [2, 281], - [2, 282], - [2, 283], - [2, 284], - [2, 285], - [2, 286], - [2, 287], - [2, 288], - [2, 289], - [2, 290], - [2, 291], - [2, 292], - [2, 293], - [2, 294], - [2, 295], - [2, 296], - [2, 297], - [2, 298], - [2, 299], - [2, 300], - [2, 301], - [2, 302], - [2, 303], - [2, 304], - [2, 305], - [2, 306], - [2, 307], - [2, 308], - [2, 309], - [2, 310], - [2, 311], - [2, 312], - [2, 313], - [2, 314], - [2, 315], - [2, 316], - [2, 317], - [2, 318], - [2, 319], - [2, 320], - [2, 321], - [2, 322], - [2, 323], - [2, 324], - [2, 325], - [2, 326], - [2, 327], - [2, 328], - [2, 329], - [2, 330], - [2, 331], - [2, 332], - [2, 333], - [2, 334], - [2, 335], - [2, 336], - [2, 337], - [2, 338], - [2, 339], - [2, 340], - [2, 341], - [2, 342], - [2, 343], - [2, 344], - [2, 345], - [2, 346], - [2, 347], - [2, 348], - [2, 349], - [2, 350], - [2, 351], - [2, 352], - [2, 353], - [2, 354], - [2, 355], - [2, 356], - [2, 357], - [2, 358], - [2, 359], - [2, 360], - [2, 361], - [2, 362], - [2, 363], - [2, 364], - [2, 365], - [2, 366], - [2, 367], - [2, 368], - [2, 369], - [2, 370], - [2, 371], - [2, 372], - [2, 373], - [2, 374], - [2, 375], - [2, 376], - [2, 377], - [2, 378], - [2, 379], - [2, 380], - [2, 381], - [2, 382], - [2, 383], - [2, 384], - [2, 385], - [2, 386], - [2, 387], - [2, 388], - [2, 389], - [2, 390], - [2, 391], - [2, 392], - [2, 393], - [2, 394], - [2, 395], - [2, 396], - [2, 397], - [2, 398], - [2, 399], - [2, 400], - [2, 401], - [2, 402], - [2, 403], - [2, 404], - [2, 405], - [2, 406], - [2, 407], - [2, 408], - [2, 409], - [2, 410], - [2, 411], - [2, 412], - [2, 413], - [2, 414], - [2, 415], - [2, 416], - [2, 417], - [2, 418], - [2, 419], - [2, 420], - [2, 421], - [2, 422], - [2, 423], - [2, 424], - [2, 425], - [2, 426], - [2, 427], - [2, 428], - [2, 429], - [2, 430], - [2, 431], - [2, 432], - [2, 433], - [2, 434], - [2, 435], - [2, 436], - [2, 437], - [2, 438], - [2, 439], - [2, 440], - [2, 441], - [2, 442], - [2, 443], - [2, 444], - [2, 445], - [2, 446], - [2, 447], - [2, 448], - [2, 449], - [2, 450], - [2, 451], - [2, 452], - [2, 453], - [2, 454], - [2, 455], - [2, 456], - [2, 457], - [2, 458], - [2, 459], - [2, 460], - [2, 461], - [2, 462], - [2, 463], - [2, 464], - [2, 465], - [2, 466], - [2, 467], - [2, 468], - [2, 469], - [2, 470], - [2, 471], - [2, 472], - [2, 473], - [2, 474], - [2, 475], - [2, 476], - [2, 477], - [2, 478], - [2, 479], - [2, 480], - [2, 481], - [2, 482], - [2, 483], - [2, 484], - [2, 485], - [2, 486], - [2, 487], - [2, 488], - [2, 489], - [2, 490], - [2, 491], - [2, 492], - [2, 493], - [2, 494], - [2, 495], - [2, 496], - [2, 497], - [2, 498], - [2, 499], - [2, 500], - [2, 501], - [2, 502], - [2, 503], - [3, 2], - [3, 3], - [3, 4], - [3, 5], - [3, 6], - [3, 7], - [3, 8], - [3, 9], - [3, 10], - [3, 11], - [3, 12], - [3, 13], - [3, 14], - [3, 15], - [3, 16], - [3, 17], - [3, 18], - [3, 19], - [3, 20], - [3, 21], - [3, 22], - [3, 23], - [3, 24], - [3, 25], - [3, 26], - [3, 27], - [3, 28], - [3, 29], - [3, 30], - [3, 31], - [3, 32], - [3, 33], - [3, 34], - [3, 35], - [3, 36], - [3, 37], - [3, 38], - [3, 39], - [3, 40], - [3, 41], - [3, 42], - [3, 43], - [3, 44], - [3, 45], - [3, 46], - [3, 47], - [3, 48], - [3, 49], - [3, 50], - [3, 51], - [3, 52], - [3, 53], - [3, 54], - [3, 55], - [3, 56], - [3, 57], - [3, 58], - [3, 59], - [3, 60], - [3, 61], - [3, 62], - [3, 63], - [3, 64], - [3, 65], - [3, 66], - [3, 67], - [3, 68], - [3, 69], - [3, 70], - [3, 71], - [3, 72], - [3, 73], - [3, 74], - [3, 75], - [3, 76], - [3, 77], - [3, 78], - [3, 79], - [3, 80], - [3, 81], - [3, 82], - [3, 83], - [3, 84], - [3, 85], - [3, 86], - [3, 87], - [3, 88], - [3, 89], - [3, 90], - [3, 91], - [3, 92], - [3, 93], - [3, 94], - [3, 95], - [3, 96], - [3, 97], - [3, 98], - [3, 99], - [3, 100], - [3, 101], - [3, 102], - [3, 103], - [3, 104], - [3, 105], - [3, 106], - [3, 107], - [3, 108], - [3, 109], - [3, 110], - [3, 111], - [3, 112], - [3, 113], - [3, 114], - [3, 115], - [3, 116], - [3, 117], - [3, 118], - [3, 119], - [3, 120], - [3, 121], - [3, 122], - [3, 123], - [3, 124], - [3, 125], - [3, 126], - [3, 127], - [3, 128], - [3, 129], - [3, 130], - [3, 131], - [3, 132], - [3, 133], - [3, 134], - [3, 135], - [3, 136], - [3, 137], - [3, 138], - [3, 139], - [3, 140], - [3, 141], - [3, 142], - [3, 143], - [3, 144], - [3, 145], - [3, 146], - [3, 147], - [3, 148], - [3, 149], - [3, 150], - [3, 151], - [3, 152], - [3, 153], - [3, 154], - [3, 155], - [3, 156], - [3, 157], - [3, 158], - [3, 159], - [3, 160], - [3, 161], - [3, 162], - [3, 163], - [3, 164], - [3, 165], - [3, 166], - [3, 167], - [3, 168], - [3, 169], - [3, 170], - [3, 171], - [3, 172], - [3, 173], - [3, 174], - [3, 175], - [3, 176], - [3, 177], - [3, 178], - [3, 179], - [3, 180], - [3, 181], - [3, 182], - [3, 183], - [3, 184], - [3, 185], - [3, 186], - [3, 187], - [3, 188], - [3, 189], - [3, 190], - [3, 191], - [3, 192], - [3, 193], - [3, 194], - [3, 195], - [3, 196], - [3, 197], - [3, 198], - [3, 199], - [3, 200], - [3, 201], - [3, 202], - [3, 203], - [3, 204], - [3, 205], - [3, 206], - [3, 207], - [3, 208], - [3, 209], - [3, 210], - [3, 211], - [3, 212], - [3, 213], - [3, 214], - [3, 215], - [3, 216], - [3, 217], - [3, 218], - [3, 219], - [3, 220], - [3, 221], - [3, 222], - [3, 223], - [3, 224], - [3, 225], - [3, 226], - [3, 227], - [3, 228], - [3, 229], - [3, 230], - [3, 231], - [3, 232], - [3, 233], - [3, 234], - [3, 235], - [3, 236], - [3, 237], - [3, 238], - [3, 239], - [3, 240], - [3, 241], - [3, 242], - [3, 243], - [3, 244], - [3, 245], - [3, 246], - [3, 247], - [3, 248], - [3, 249], - [3, 250], - [3, 251], - [3, 252], - [3, 253], - [3, 254], - [3, 255], - [3, 256], - [3, 257], - [3, 258], - [3, 259], - [3, 260], - [3, 261], - [3, 262], - [3, 263], - [3, 264], - [3, 265], - [3, 266], - [3, 267], - [3, 268], - [3, 269], - [3, 270], - [3, 271], - [3, 272], - [3, 273], - [3, 274], - [3, 275], - [3, 276], - [3, 277], - [3, 278], - [3, 279], - [3, 280], - [3, 281], - [3, 282], - [3, 283], - [3, 284], - [3, 285], - [3, 286], - [3, 287], - [3, 288], - [3, 289], - [3, 290], - [3, 291], - [3, 292], - [3, 293], - [3, 294], - [3, 295], - [3, 296], - [3, 297], - [3, 298], - [3, 299], - [3, 300], - [3, 301], - [3, 302], - [3, 303], - [3, 304], - [3, 305], - [3, 306], - [3, 307], - [3, 308], - [3, 309], - [3, 310], - [3, 311], - [3, 312], - [3, 313], - [3, 314], - [3, 315], - [3, 316], - [3, 317], - [3, 318], - [3, 319], - [3, 320], - [3, 321], - [3, 322], - [3, 323], - [3, 324], - [3, 325], - [3, 326], - [3, 327], - [3, 328], - [3, 329], - [3, 330], - [3, 331], - [3, 332], - [3, 333], - [3, 334], - [3, 335], - [3, 336], - [3, 337], - [3, 338], - [3, 339], - [3, 340], - [3, 341], - [3, 342], - [3, 343], - [3, 344], - [3, 345], - [3, 346], - [3, 347], - [3, 348], - [3, 349], - [3, 350], - [3, 351], - [3, 352], - [3, 353], - [3, 354], - [3, 355], - [3, 356], - [3, 357], - [3, 358], - [3, 359], - [3, 360], - [3, 361], - [3, 362], - [3, 363], - [3, 364], - [3, 365], - [3, 366], - [3, 367], - [3, 368], - [3, 369], - [3, 370], - [3, 371], - [3, 372], - [3, 373], - [3, 374], - [3, 375], - [3, 376], - [3, 377], - [3, 378], - [3, 379], - [3, 380], - [3, 381], - [3, 382], - [3, 383], - [3, 384], - [3, 385], - [3, 386], - [3, 387], - [3, 388], - [3, 389], - [3, 390], - [3, 391], - [3, 392], - [3, 393], - [3, 394], - [3, 395], - [3, 396], - [3, 397], - [3, 398], - [3, 399], - [3, 400], - [3, 401], - [3, 402], - [3, 403], - [3, 404], - [3, 405], - [3, 406], - [3, 407], - [3, 408], - [3, 409], - [3, 410], - [3, 411], - [3, 412], - [3, 413], - [3, 414], - [3, 415], - [3, 416], - [3, 417], - [3, 418], - [3, 419], - [3, 420], - [3, 421], - [3, 422], - [3, 423], - [3, 424], - [3, 425], - [3, 426], - [3, 427], - [3, 428], - [3, 429], - [3, 430], - [3, 431], - [3, 432], - [3, 433], - [3, 434], - [3, 435], - [3, 436], - [3, 437], - [3, 438], - [3, 439], - [3, 440], - [3, 441], - [3, 442], - [3, 443], - [3, 444], - [3, 445], - [3, 446], - [3, 447], - [3, 448], - [3, 449], - [3, 450], - [3, 451], - [3, 452], - [3, 453], - [3, 454], - [3, 455], - [3, 456], - [3, 457], - [3, 458], - [3, 459], - [3, 460], - [3, 461], - [3, 462], - [3, 463], - [3, 464], - [3, 465], - [3, 466], - [3, 467], - [3, 468], - [3, 469], - [3, 470], - [3, 471], - [3, 472], - [3, 473], - [3, 474], - [3, 475], - [3, 476], - [3, 477], - [3, 478], - [3, 479], - [3, 480], - [3, 481], - [3, 482], - [3, 483], - [3, 484], - [3, 485], - [3, 486], - [3, 487], - [3, 488], - [3, 489], - [3, 490], - [3, 491], - [3, 492], - [3, 493], - [3, 494], - [3, 495], - [3, 496], - [3, 497], - [3, 498], - [3, 499], - [3, 500], - [3, 501], - [3, 502], - [3, 503], - [4, 2], - [4, 3], - [4, 4], - [4, 5], - [4, 6], - [4, 7], - [4, 8], - [4, 9], - [4, 10], - [4, 11], - [4, 12], - [4, 13], - [4, 14], - [4, 15], - [4, 16], - [4, 17], - [4, 18], - [4, 19], - [4, 20], - [4, 21], - [4, 22], - [4, 23], - [4, 24], - [4, 25], - [4, 26], - [4, 27], - [4, 28], - [4, 29], - [4, 30], - [4, 31], - [4, 32], - [4, 33], - [4, 34], - [4, 35], - [4, 36], - [4, 37], - [4, 38], - [4, 39], - [4, 40], - [4, 41], - [4, 42], - [4, 43], - [4, 44], - [4, 45], - [4, 46], - [4, 47], - [4, 48], - [4, 49], - [4, 50], - [4, 51], - [4, 52], - [4, 53], - [4, 54], - [4, 55], - [4, 56], - [4, 57], - [4, 58], - [4, 59], - [4, 60], - [4, 61], - [4, 62], - [4, 63], - [4, 64], - [4, 65], - [4, 66], - [4, 67], - [4, 68], - [4, 69], - [4, 70], - [4, 71], - [4, 72], - [4, 73], - [4, 74], - [4, 75], - [4, 76], - [4, 77], - [4, 78], - [4, 79], - [4, 80], - [4, 81], - [4, 82], - [4, 83], - [4, 84], - [4, 85], - [4, 86], - [4, 87], - [4, 88], - [4, 89], - [4, 90], - [4, 91], - [4, 92], - [4, 93], - [4, 94], - [4, 95], - [4, 96], - [4, 97], - [4, 98], - [4, 99], - [4, 100], - [4, 101], - [4, 102], - [4, 103], - [4, 104], - [4, 105], - [4, 106], - [4, 107], - [4, 108], - [4, 109], - [4, 110], - [4, 111], - [4, 112], - [4, 113], - [4, 114], - [4, 115], - [4, 116], - [4, 117], - [4, 118], - [4, 119], - [4, 120], - [4, 121], - [4, 122], - [4, 123], - [4, 124], - [4, 125], - [4, 126], - [4, 127], - [4, 128], - [4, 129], - [4, 130], - [4, 131], - [4, 132], - [4, 133], - [4, 134], - [4, 135], - [4, 136], - [4, 137], - [4, 138], - [4, 139], - [4, 140], - [4, 141], - [4, 142], - [4, 143], - [4, 144], - [4, 145], - [4, 146], - [4, 147], - [4, 148], - [4, 149], - [4, 150], - [4, 151], - [4, 152], - [4, 153], - [4, 154], - [4, 155], - [4, 156], - [4, 157], - [4, 158], - [4, 159], - [4, 160], - [4, 161], - [4, 162], - [4, 163], - [4, 164], - [4, 165], - [4, 166], - [4, 167], - [4, 168], - [4, 169], - [4, 170], - [4, 171], - [4, 172], - [4, 173], - [4, 174], - [4, 175], - [4, 176], - [4, 177], - [4, 178], - [4, 179], - [4, 180], - [4, 181], - [4, 182], - [4, 183], - [4, 184], - [4, 185], - [4, 186], - [4, 187], - [4, 188], - [4, 189], - [4, 190], - [4, 191], - [4, 192], - [4, 193], - [4, 194], - [4, 195], - [4, 196], - [4, 197], - [4, 198], - [4, 199], - [4, 200], - [4, 201], - [4, 202], - [4, 203], - [4, 204], - [4, 205], - [4, 206], - [4, 207], - [4, 208], - [4, 209], - [4, 210], - [4, 211], - [4, 212], - [4, 213], - [4, 214], - [4, 215], - [4, 216], - [4, 217], - [4, 218], - [4, 219], - [4, 220], - [4, 221], - [4, 222], - [4, 223], - [4, 224], - [4, 225], - [4, 226], - [4, 227], - [4, 228], - [4, 229], - [4, 230], - [4, 231], - [4, 232], - [4, 233], - [4, 234], - [4, 235], - [4, 236], - [4, 237], - [4, 238], - [4, 239], - [4, 240], - [4, 241], - [4, 242], - [4, 243], - [4, 244], - [4, 245], - [4, 246], - [4, 247], - [4, 248], - [4, 249], - [4, 250], - [4, 251], - [4, 252], - [4, 253], - [4, 254], - [4, 255], - [4, 256], - [4, 257], - [4, 258], - [4, 259], - [4, 260], - [4, 261], - [4, 262], - [4, 263], - [4, 264], - [4, 265], - [4, 266], - [4, 267], - [4, 268], - [4, 269], - [4, 270], - [4, 271], - [4, 272], - [4, 273], - [4, 274], - [4, 275], - [4, 276], - [4, 277], - [4, 278], - [4, 279], - [4, 280], - [4, 281], - [4, 282], - [4, 283], - [4, 284], - [4, 285], - [4, 286], - [4, 287], - [4, 288], - [4, 289], - [4, 290], - [4, 291], - [4, 292], - [4, 293], - [4, 294], - [4, 295], - [4, 296], - [4, 297], - [4, 298], - [4, 299], - [4, 300], - [4, 301], - [4, 302], - [4, 303], - [4, 304], - [4, 305], - [4, 306], - [4, 307], - [4, 308], - [4, 309], - [4, 310], - [4, 311], - [4, 312], - [4, 313], - [4, 314], - [4, 315], - [4, 316], - [4, 317], - [4, 318], - [4, 319], - [4, 320], - [4, 321], - [4, 322], - [4, 323], - [4, 324], - [4, 325], - [4, 326], - [4, 327], - [4, 328], - [4, 329], - [4, 330], - [4, 331], - [4, 332], - [4, 333], - [4, 334], - [4, 335], - [4, 336], - [4, 337], - [4, 338], - [4, 339], - [4, 340], - [4, 341], - [4, 342], - [4, 343], - [4, 344], - [4, 345], - [4, 346], - [4, 347], - [4, 348], - [4, 349], - [4, 350], - [4, 351], - [4, 352], - [4, 353], - [4, 354], - [4, 355], - [4, 356], - [4, 357], - [4, 358], - [4, 359], - [4, 360], - [4, 361], - [4, 362], - [4, 363], - [4, 364], - [4, 365], - [4, 366], - [4, 367], - [4, 368], - [4, 369], - [4, 370], - [4, 371], - [4, 372], - [4, 373], - [4, 374], - [4, 375], - [4, 376], - [4, 377], - [4, 378], - [4, 379], - [4, 380], - [4, 381], - [4, 382], - [4, 383], - [4, 384], - [4, 385], - [4, 386], - [4, 387], - [4, 388], - [4, 389], - [4, 390], - [4, 391], - [4, 392], - [4, 393], - [4, 394], - [4, 395], - [4, 396], - [4, 397], - [4, 398], - [4, 399], - [4, 400], - [4, 401], - [4, 402], - [4, 403], - [4, 404], - [4, 405], - [4, 406], - [4, 407], - [4, 408], - [4, 409], - [4, 410], - [4, 411], - [4, 412], - [4, 413], - [4, 414], - [4, 415], - [4, 416], - [4, 417], - [4, 418], - [4, 419], - [4, 420], - [4, 421], - [4, 422], - [4, 423], - [4, 424], - [4, 425], - [4, 426], - [4, 427], - [4, 428], - [4, 429], - [4, 430], - [4, 431], - [4, 432], - [4, 433], - [4, 434], - [4, 435], - [4, 436], - [4, 437], - [4, 438], - [4, 439], - [4, 440], - [4, 441], - [4, 442], - [4, 443], - [4, 444], - [4, 445], - [4, 446], - [4, 447], - [4, 448], - [4, 449], - [4, 450], - [4, 451], - [4, 452], - [4, 453], - [4, 454], - [4, 455], - [4, 456], - [4, 457], - [4, 458], - [4, 459], - [4, 460], - [4, 461], - [4, 462], - [4, 463], - [4, 464], - [4, 465], - [4, 466], - [4, 467], - [4, 468], - [4, 469], - [4, 470], - [4, 471], - [4, 472], - [4, 473], - [4, 474], - [4, 475], - [4, 476], - [4, 477], - [4, 478], - [4, 479], - [4, 480], - [4, 481], - [4, 482], - [4, 483], - [4, 484], - [4, 485], - [4, 486], - [4, 487], - [4, 488], - [4, 489], - [4, 490], - [4, 491], - [4, 492], - [4, 493], - [4, 494], - [4, 495], - [4, 496], - [4, 497], - [4, 498], - [4, 499], - [4, 500], - [4, 501], - [4, 502], - [4, 503], - [5, 2], - [5, 3], - [5, 4], - [5, 5], - [5, 6], - [5, 7], - [5, 8], - [5, 9], - [5, 10], - [5, 11], - [5, 12], - [5, 13], - [5, 14], - [5, 15], - [5, 16], - [5, 17], - [5, 18], - [5, 19], - [5, 20], - [5, 21], - [5, 22], - [5, 23], - [5, 24], - [5, 25], - [5, 26], - [5, 27], - [5, 28], - [5, 29], - [5, 30], - [5, 31], - [5, 32], - [5, 33], - [5, 34], - [5, 35], - [5, 36], - [5, 37], - [5, 38], - [5, 39], - [5, 40], - [5, 41], - [5, 42], - [5, 43], - [5, 44], - [5, 45], - [5, 46], - [5, 47], - [5, 48], - [5, 49], - [5, 50], - [5, 51], - [5, 52], - [5, 53], - [5, 54], - [5, 55], - [5, 56], - [5, 57], - [5, 58], - [5, 59], - [5, 60], - [5, 61], - [5, 62], - [5, 63], - [5, 64], - [5, 65], - [5, 66], - [5, 67], - [5, 68], - [5, 69], - [5, 70], - [5, 71], - [5, 72], - [5, 73], - [5, 74], - [5, 75], - [5, 76], - [5, 77], - [5, 78], - [5, 79], - [5, 80], - [5, 81], - [5, 82], - [5, 83], - [5, 84], - [5, 85], - [5, 86], - [5, 87], - [5, 88], - [5, 89], - [5, 90], - [5, 91], - [5, 92], - [5, 93], - [5, 94], - [5, 95], - [5, 96], - [5, 97], - [5, 98], - [5, 99], - [5, 100], - [5, 101], - [5, 102], - [5, 103], - [5, 104], - [5, 105], - [5, 106], - [5, 107], - [5, 108], - [5, 109], - [5, 110], - [5, 111], - [5, 112], - [5, 113], - [5, 114], - [5, 115], - [5, 116], - [5, 117], - [5, 118], - [5, 119], - [5, 120], - [5, 121], - [5, 122], - [5, 123], - [5, 124], - [5, 125], - [5, 126], - [5, 127], - [5, 128], - [5, 129], - [5, 130], - [5, 131], - [5, 132], - [5, 133], - [5, 134], - [5, 135], - [5, 136], - [5, 137], - [5, 138], - [5, 139], - [5, 140], - [5, 141], - [5, 142], - [5, 143], - [5, 144], - [5, 145], - [5, 146], - [5, 147], - [5, 148], - [5, 149], - [5, 150], - [5, 151], - [5, 152], - [5, 153], - [5, 154], - [5, 155], - [5, 156], - [5, 157], - [5, 158], - [5, 159], - [5, 160], - [5, 161], - [5, 162], - [5, 163], - [5, 164], - [5, 165], - [5, 166], - [5, 167], - [5, 168], - [5, 169], - [5, 170], - [5, 171], - [5, 172], - [5, 173], - [5, 174], - [5, 175], - [5, 176], - [5, 177], - [5, 178], - [5, 179], - [5, 180], - [5, 181], - [5, 182], - [5, 183], - [5, 184], - [5, 185], - [5, 186], - [5, 187], - [5, 188], - [5, 189], - [5, 190], - [5, 191], - [5, 192], - [5, 193], - [5, 194], - [5, 195], - [5, 196], - [5, 197], - [5, 198], - [5, 199], - [5, 200], - [5, 201], - [5, 202], - [5, 203], - [5, 204], - [5, 205], - [5, 206], - [5, 207], - [5, 208], - [5, 209], - [5, 210], - [5, 211], - [5, 212], - [5, 213], - [5, 214], - [5, 215], - [5, 216], - [5, 217], - [5, 218], - [5, 219], - [5, 220], - [5, 221], - [5, 222], - [5, 223], - [5, 224], - [5, 225], - [5, 226], - [5, 227], - [5, 228], - [5, 229], - [5, 230], - [5, 231], - [5, 232], - [5, 233], - [5, 234], - [5, 235], - [5, 236], - [5, 237], - [5, 238], - [5, 239], - [5, 240], - [5, 241], - [5, 242], - [5, 243], - [5, 244], - [5, 245], - [5, 246], - [5, 247], - [5, 248], - [5, 249], - [5, 250], - [5, 251], - [5, 252], - [5, 253], - [5, 254], - [5, 255], - [5, 256], - [5, 257], - [5, 258], - [5, 259], - [5, 260], - [5, 261], - [5, 262], - [5, 263], - [5, 264], - [5, 265], - [5, 266], - [5, 267], - [5, 268], - [5, 269], - [5, 270], - [5, 271], - [5, 272], - [5, 273], - [5, 274], - [5, 275], - [5, 276], - [5, 277], - [5, 278], - [5, 279], - [5, 280], - [5, 281], - [5, 282], - [5, 283], - [5, 284], - [5, 285], - [5, 286], - [5, 287], - [5, 288], - [5, 289], - [5, 290], - [5, 291], - [5, 292], - [5, 293], - [5, 294], - [5, 295], - [5, 296], - [5, 297], - [5, 298], - [5, 299], - [5, 300], - [5, 301], - [5, 302], - [5, 303], - [5, 304], - [5, 305], - [5, 306], - [5, 307], - [5, 308], - [5, 309], - [5, 310], - [5, 311], - [5, 312], - [5, 313], - [5, 314], - [5, 315], - [5, 316], - [5, 317], - [5, 318], - [5, 319], - [5, 320], - [5, 321], - [5, 322], - [5, 323], - [5, 324], - [5, 325], - [5, 326], - [5, 327], - [5, 328], - [5, 329], - [5, 330], - [5, 331], - [5, 332], - [5, 333], - [5, 334], - [5, 335], - [5, 336], - [5, 337], - [5, 338], - [5, 339], - [5, 340], - [5, 341], - [5, 342], - [5, 343], - [5, 344], - [5, 345], - [5, 346], - [5, 347], - [5, 348], - [5, 349], - [5, 350], - [5, 351], - [5, 352], - [5, 353], - [5, 354], - [5, 355], - [5, 356], - [5, 357], - [5, 358], - [5, 359], - [5, 360], - [5, 361], - [5, 362], - [5, 363], - [5, 364], - [5, 365], - [5, 366], - [5, 367], - [5, 368], - [5, 369], - [5, 370], - [5, 371], - [5, 372], - [5, 373], - [5, 374], - [5, 375], - [5, 376], - [5, 377], - [5, 378], - [5, 379], - [5, 380], - [5, 381], - [5, 382], - [5, 383], - [5, 384], - [5, 385], - [5, 386], - [5, 387], - [5, 388], - [5, 389], - [5, 390], - [5, 391], - [5, 392], - [5, 393], - [5, 394], - [5, 395], - [5, 396], - [5, 397], - [5, 398], - [5, 399], - [5, 400], - [5, 401], - [5, 402], - [5, 403], - [5, 404], - [5, 405], - [5, 406], - [5, 407], - [5, 408], - [5, 409], - [5, 410], - [5, 411], - [5, 412], - [5, 413], - [5, 414], - [5, 415], - [5, 416], - [5, 417], - [5, 418], - [5, 419], - [5, 420], - [5, 421], - [5, 422], - [5, 423], - [5, 424], - [5, 425], - [5, 426], - [5, 427], - [5, 428], - [5, 429], - [5, 430], - [5, 431], - [5, 432], - [5, 433], - [5, 434], - [5, 435], - [5, 436], - [5, 437], - [5, 438], - [5, 439], - [5, 440], - [5, 441], - [5, 442], - [5, 443], - [5, 444], - [5, 445], - [5, 446], - [5, 447], - [5, 448], - [5, 449], - [5, 450], - [5, 451], - [5, 452], - [5, 453], - [5, 454], - [5, 455], - [5, 456], - [5, 457], - [5, 458], - [5, 459], - [5, 460], - [5, 461], - [5, 462], - [5, 463], - [5, 464], - [5, 465], - [5, 466], - [5, 467], - [5, 468], - [5, 469], - [5, 470], - [5, 471], - [5, 472], - [5, 473], - [5, 474], - [5, 475], - [5, 476], - [5, 477], - [5, 478], - [5, 479], - [5, 480], - [5, 481], - [5, 482], - [5, 483], - [5, 484], - [5, 485], - [5, 486], - [5, 487], - [5, 488], - [5, 489], - [5, 490], - [5, 491], - [5, 492], - [5, 493], - [5, 494], - [5, 495], - [5, 496], - [5, 497], - [5, 498], - [5, 499], - [5, 500], - [5, 501], - [5, 502], - [5, 503], - [6, 2], - [6, 3], - [6, 4], - [6, 5], - [6, 6], - [6, 7], - [6, 8], - [6, 9], - [6, 10], - [6, 11], - [6, 12], - [6, 13], - [6, 14], - [6, 15], - [6, 16], - [6, 17], - [6, 18], - [6, 19], - [6, 20], - [6, 21], - [6, 22], - [6, 23], - [6, 24], - [6, 25], - [6, 26], - [6, 27], - [6, 28], - [6, 29], - [6, 30], - [6, 31], - [6, 32], - [6, 33], - [6, 34], - [6, 35], - [6, 36], - [6, 37], - [6, 38], - [6, 39], - [6, 40], - [6, 41], - [6, 42], - [6, 43], - [6, 44], - [6, 45], - [6, 46], - [6, 47], - [6, 48], - [6, 49], - [6, 50], - [6, 51], - [6, 52], - [6, 53], - [6, 54], - [6, 55], - [6, 56], - [6, 57], - [6, 58], - [6, 59], - [6, 60], - [6, 61], - [6, 62], - [6, 63], - [6, 64], - [6, 65], - [6, 66], - [6, 67], - [6, 68], - [6, 69], - [6, 70], - [6, 71], - [6, 72], - [6, 73], - [6, 74], - [6, 75], - [6, 76], - [6, 77], - [6, 78], - [6, 79], - [6, 80], - [6, 81], - [6, 82], - [6, 83], - [6, 84], - [6, 85], - [6, 86], - [6, 87], - [6, 88], - [6, 89], - [6, 90], - [6, 91], - [6, 92], - [6, 93], - [6, 94], - [6, 95], - [6, 96], - [6, 97], - [6, 98], - [6, 99], - [6, 100], - [6, 101], - [6, 102], - [6, 103], - [6, 104], - [6, 105], - [6, 106], - [6, 107], - [6, 108], - [6, 109], - [6, 110], - [6, 111], - [6, 112], - [6, 113], - [6, 114], - [6, 115], - [6, 116], - [6, 117], - [6, 118], - [6, 119], - [6, 120], - [6, 121], - [6, 122], - [6, 123], - [6, 124], - [6, 125], - [6, 126], - [6, 127], - [6, 128], - [6, 129], - [6, 130], - [6, 131], - [6, 132], - [6, 133], - [6, 134], - [6, 135], - [6, 136], - [6, 137], - [6, 138], - [6, 139], - [6, 140], - [6, 141], - [6, 142], - [6, 143], - [6, 144], - [6, 145], - [6, 146], - [6, 147], - [6, 148], - [6, 149], - [6, 150], - [6, 151], - [6, 152], - [6, 153], - [6, 154], - [6, 155], - [6, 156], - [6, 157], - [6, 158], - [6, 159], - [6, 160], - [6, 161], - [6, 162], - [6, 163], - [6, 164], - [6, 165], - [6, 166], - [6, 167], - [6, 168], - [6, 169], - [6, 170], - [6, 171], - [6, 172], - [6, 173], - [6, 174], - [6, 175], - [6, 176], - [6, 177], - [6, 178], - [6, 179], - [6, 180], - [6, 181], - [6, 182], - [6, 183], - [6, 184], - [6, 185], - [6, 186], - [6, 187], - [6, 188], - [6, 189], - [6, 190], - [6, 191], - [6, 192], - [6, 193], - [6, 194], - [6, 195], - [6, 196], - [6, 197], - [6, 198], - [6, 199], - [6, 200], - [6, 201], - [6, 202], - [6, 203], - [6, 204], - [6, 205], - [6, 206], - [6, 207], - [6, 208], - [6, 209], - [6, 210], - [6, 211], - [6, 212], - [6, 213], - [6, 214], - [6, 215], - [6, 216], - [6, 217], - [6, 218], - [6, 219], - [6, 220], - [6, 221], - [6, 222], - [6, 223], - [6, 224], - [6, 225], - [6, 226], - [6, 227], - [6, 228], - [6, 229], - [6, 230], - [6, 231], - [6, 232], - [6, 233], - [6, 234], - [6, 235], - [6, 236], - [6, 237], - [6, 238], - [6, 239], - [6, 240], - [6, 241], - [6, 242], - [6, 243], - [6, 244], - [6, 245], - [6, 246], - [6, 247], - [6, 248], - [6, 249], - [6, 250], - [6, 251], - [6, 252], - [6, 253], - [6, 254], - [6, 255], - [6, 256], - [6, 257], - [6, 258], - [6, 259], - [6, 260], - [6, 261], - [6, 262], - [6, 263], - [6, 264], - [6, 265], - [6, 266], - [6, 267], - [6, 268], - [6, 269], - [6, 270], - [6, 271], - [6, 272], - [6, 273], - [6, 274], - [6, 275], - [6, 276], - [6, 277], - [6, 278], - [6, 279], - [6, 280], - [6, 281], - [6, 282], - [6, 283], - [6, 284], - [6, 285], - [6, 286], - [6, 287], - [6, 288], - [6, 289], - [6, 290], - [6, 291], - [6, 292], - [6, 293], - [6, 294], - [6, 295], - [6, 296], - [6, 297], - [6, 298], - [6, 299], - [6, 300], - [6, 301], - [6, 302], - [6, 303], - [6, 304], - [6, 305], - [6, 306], - [6, 307], - [6, 308], - [6, 309], - [6, 310], - [6, 311], - [6, 312], - [6, 313], - [6, 314], - [6, 315], - [6, 316], - [6, 317], - [6, 318], - [6, 319], - [6, 320], - [6, 321], - [6, 322], - [6, 323], - [6, 324], - [6, 325], - [6, 326], - [6, 327], - [6, 328], - [6, 329], - [6, 330], - [6, 331], - [6, 332], - [6, 333], - [6, 334], - [6, 335], - [6, 336], - [6, 337], - [6, 338], - [6, 339], - [6, 340], - [6, 341], - [6, 342], - [6, 343], - [6, 344], - [6, 345], - [6, 346], - [6, 347], - [6, 348], - [6, 349], - [6, 350], - [6, 351], - [6, 352], - [6, 353], - [6, 354], - [6, 355], - [6, 356], - [6, 357], - [6, 358], - [6, 359], - [6, 360], - [6, 361], - [6, 362], - [6, 363], - [6, 364], - [6, 365], - [6, 366], - [6, 367], - [6, 368], - [6, 369], - [6, 370], - [6, 371], - [6, 372], - [6, 373], - [6, 374], - [6, 375], - [6, 376], - [6, 377], - [6, 378], - [6, 379], - [6, 380], - [6, 381], - [6, 382], - [6, 383], - [6, 384], - [6, 385], - [6, 386], - [6, 387], - [6, 388], - [6, 389], - [6, 390], - [6, 391], - [6, 392], - [6, 393], - [6, 394], - [6, 395], - [6, 396], - [6, 397], - [6, 398], - [6, 399], - [6, 400], - [6, 401], - [6, 402], - [6, 403], - [6, 404], - [6, 405], - [6, 406], - [6, 407], - [6, 408], - [6, 409], - [6, 410], - [6, 411], - [6, 412], - [6, 413], - [6, 414], - [6, 415], - [6, 416], - [6, 417], - [6, 418], - [6, 419], - [6, 420], - [6, 421], - [6, 422], - [6, 423], - [6, 424], - [6, 425], - [6, 426], - [6, 427], - [6, 428], - [6, 429], - [6, 430], - [6, 431], - [6, 432], - [6, 433], - [6, 434], - [6, 435], - [6, 436], - [6, 437], - [6, 438], - [6, 439], - [6, 440], - [6, 441], - [6, 442], - [6, 443], - [6, 444], - [6, 445], - [6, 446], - [6, 447], - [6, 448], - [6, 449], - [6, 450], - [6, 451], - [6, 452], - [6, 453], - [6, 454], - [6, 455], - [6, 456], - [6, 457], - [6, 458], - [6, 459], - [6, 460], - [6, 461], - [6, 462], - [6, 463], - [6, 464], - [6, 465], - [6, 466], - [6, 467], - [6, 468], - [6, 469], - [6, 470], - [6, 471], - [6, 472], - [6, 473], - [6, 474], - [6, 475], - [6, 476], - [6, 477], - [6, 478], - [6, 479], - [6, 480], - [6, 481], - [6, 482], - [6, 483], - [6, 484], - [6, 485], - [6, 486], - [6, 487], - [6, 488], - [6, 489], - [6, 490], - [6, 491], - [6, 492], - [6, 493], - [6, 494], - [6, 495], - [6, 496], - [6, 497], - [6, 498], - [6, 499], - [6, 500], - [6, 501], - [6, 502], - [6, 503], - [7, 2], - [7, 3], - [7, 4], - [7, 5], - [7, 6], - [7, 7], - [7, 8], - [7, 9], - [7, 10], - [7, 11], - [7, 12], - [7, 13], - [7, 14], - [7, 15], - [7, 16], - [7, 17], - [7, 18], - [7, 19], - [7, 20], - [7, 21], - [7, 22], - [7, 23], - [7, 24], - [7, 25], - [7, 26], - [7, 27], - [7, 28], - [7, 29], - [7, 30], - [7, 31], - [7, 32], - [7, 33], - [7, 34], - [7, 35], - [7, 36], - [7, 37], - [7, 38], - [7, 39], - [7, 40], - [7, 41], - [7, 42], - [7, 43], - [7, 44], - [7, 45], - [7, 46], - [7, 47], - [7, 48], - [7, 49], - [7, 50], - [7, 51], - [7, 52], - [7, 53], - [7, 54], - [7, 55], - [7, 56], - [7, 57], - [7, 58], - [7, 59], - [7, 60], - [7, 61], - [7, 62], - [7, 63], - [7, 64], - [7, 65], - [7, 66], - [7, 67], - [7, 68], - [7, 69], - [7, 70], - [7, 71], - [7, 72], - [7, 73], - [7, 74], - [7, 75], - [7, 76], - [7, 77], - [7, 78], - [7, 79], - [7, 80], - [7, 81], - [7, 82], - [7, 83], - [7, 84], - [7, 85], - [7, 86], - [7, 87], - [7, 88], - [7, 89], - [7, 90], - [7, 91], - [7, 92], - [7, 93], - [7, 94], - [7, 95], - [7, 96], - [7, 97], - [7, 98], - [7, 99], - [7, 100], - [7, 101], - [7, 102], - [7, 103], - [7, 104], - [7, 105], - [7, 106], - [7, 107], - [7, 108], - [7, 109], - [7, 110], - [7, 111], - [7, 112], - [7, 113], - [7, 114], - [7, 115], - [7, 116], - [7, 117], - [7, 118], - [7, 119], - [7, 120], - [7, 121], - [7, 122], - [7, 123], - [7, 124], - [7, 125], - [7, 126], - [7, 127], - [7, 128], - [7, 129], - [7, 130], - [7, 131], - [7, 132], - [7, 133], - [7, 134], - [7, 135], - [7, 136], - [7, 137], - [7, 138], - [7, 139], - [7, 140], - [7, 141], - [7, 142], - [7, 143], - [7, 144], - [7, 145], - [7, 146], - [7, 147], - [7, 148], - [7, 149], - [7, 150], - [7, 151], - [7, 152], - [7, 153], - [7, 154], - [7, 155], - [7, 156], - [7, 157], - [7, 158], - [7, 159], - [7, 160], - [7, 161], - [7, 162], - [7, 163], - [7, 164], - [7, 165], - [7, 166], - [7, 167], - [7, 168], - [7, 169], - [7, 170], - [7, 171], - [7, 172], - [7, 173], - [7, 174], - [7, 175], - [7, 176], - [7, 177], - [7, 178], - [7, 179], - [7, 180], - [7, 181], - [7, 182], - [7, 183], - [7, 184], - [7, 185], - [7, 186], - [7, 187], - [7, 188], - [7, 189], - [7, 190], - [7, 191], - [7, 192], - [7, 193], - [7, 194], - [7, 195], - [7, 196], - [7, 197], - [7, 198], - [7, 199], - [7, 200], - [7, 201], - [7, 202], - [7, 203], - [7, 204], - [7, 205], - [7, 206], - [7, 207], - [7, 208], - [7, 209], - [7, 210], - [7, 211], - [7, 212], - [7, 213], - [7, 214], - [7, 215], - [7, 216], - [7, 217], - [7, 218], - [7, 219], - [7, 220], - [7, 221], - [7, 222], - [7, 223], - [7, 224], - [7, 225], - [7, 226], - [7, 227], - [7, 228], - [7, 229], - [7, 230], - [7, 231], - [7, 232], - [7, 233], - [7, 234], - [7, 235], - [7, 236], - [7, 237], - [7, 238], - [7, 239], - [7, 240], - [7, 241], - [7, 242], - [7, 243], - [7, 244], - [7, 245], - [7, 246], - [7, 247], - [7, 248], - [7, 249], - [7, 250], - [7, 251], - [7, 252], - [7, 253], - [7, 254], - [7, 255], - [7, 256], - [7, 257], - [7, 258], - [7, 259], - [7, 260], - [7, 261], - [7, 262], - [7, 263], - [7, 264], - [7, 265], - [7, 266], - [7, 267], - [7, 268], - [7, 269], - [7, 270], - [7, 271], - [7, 272], - [7, 273], - [7, 274], - [7, 275], - [7, 276], - [7, 277], - [7, 278], - [7, 279], - [7, 280], - [7, 281], - [7, 282], - [7, 283], - [7, 284], - [7, 285], - [7, 286], - [7, 287], - [7, 288], - [7, 289], - [7, 290], - [7, 291], - [7, 292], - [7, 293], - [7, 294], - [7, 295], - [7, 296], - [7, 297], - [7, 298], - [7, 299], - [7, 300], - [7, 301], - [7, 302], - [7, 303], - [7, 304], - [7, 305], - [7, 306], - [7, 307], - [7, 308], - [7, 309], - [7, 310], - [7, 311], - [7, 312], - [7, 313], - [7, 314], - [7, 315], - [7, 316], - [7, 317], - [7, 318], - [7, 319], - [7, 320], - [7, 321], - [7, 322], - [7, 323], - [7, 324], - [7, 325], - [7, 326], - [7, 327], - [7, 328], - [7, 329], - [7, 330], - [7, 331], - [7, 332], - [7, 333], - [7, 334], - [7, 335], - [7, 336], - [7, 337], - [7, 338], - [7, 339], - [7, 340], - [7, 341], - [7, 342], - [7, 343], - [7, 344], - [7, 345], - [7, 346], - [7, 347], - [7, 348], - [7, 349], - [7, 350], - [7, 351], - [7, 352], - [7, 353], - [7, 354], - [7, 355], - [7, 356], - [7, 357], - [7, 358], - [7, 359], - [7, 360], - [7, 361], - [7, 362], - [7, 363], - [7, 364], - [7, 365], - [7, 366], - [7, 367], - [7, 368], - [7, 369], - [7, 370], - [7, 371], - [7, 372], - [7, 373], - [7, 374], - [7, 375], - [7, 376], - [7, 377], - [7, 378], - [7, 379], - [7, 380], - [7, 381], - [7, 382], - [7, 383], - [7, 384], - [7, 385], - [7, 386], - [7, 387], - [7, 388], - [7, 389], - [7, 390], - [7, 391], - [7, 392], - [7, 393], - [7, 394], - [7, 395], - [7, 396], - [7, 397], - [7, 398], - [7, 399], - [7, 400], - [7, 401], - [7, 402], - [7, 403], - [7, 404], - [7, 405], - [7, 406], - [7, 407], - [7, 408], - [7, 409], - [7, 410], - [7, 411], - [7, 412], - [7, 413], - [7, 414], - [7, 415], - [7, 416], - [7, 417], - [7, 418], - [7, 419], - [7, 420], - [7, 421], - [7, 422], - [7, 423], - [7, 424], - [7, 425], - [7, 426], - [7, 427], - [7, 428], - [7, 429], - [7, 430], - [7, 431], - [7, 432], - [7, 433], - [7, 434], - [7, 435], - [7, 436], - [7, 437], - [7, 438], - [7, 439], - [7, 440], - [7, 441], - [7, 442], - [7, 443], - [7, 444], - [7, 445], - [7, 446], - [7, 447], - [7, 448], - [7, 449], - [7, 450], - [7, 451], - [7, 452], - [7, 453], - [7, 454], - [7, 455], - [7, 456], - [7, 457], - [7, 458], - [7, 459], - [7, 460], - [7, 461], - [7, 462], - [7, 463], - [7, 464], - [7, 465], - [7, 466], - [7, 467], - [7, 468], - [7, 469], - [7, 470], - [7, 471], - [7, 472], - [7, 473], - [7, 474], - [7, 475], - [7, 476], - [7, 477], - [7, 478], - [7, 479], - [7, 480], - [7, 481], - [7, 482], - [7, 483], - [7, 484], - [7, 485], - [7, 486], - [7, 487], - [7, 488], - [7, 489], - [7, 490], - [7, 491], - [7, 492], - [7, 493], - [7, 494], - [7, 495], - [7, 496], - [7, 497], - [7, 498], - [7, 499], - [7, 500], - [7, 501], - [7, 502], - [7, 503], - [11, 4] - ], - "array_output": [ - ["33", "09W", "South Capitol Street", "Washington", "DC", "USA", "38.86872333", "-77.00747583"] - ], - "formatted_code": "df = getCells((0, 2), (7, 503), first_row_header=True)\ndf = df[df[\"iata\"] == c(11, 4)].head(1)\ndf = df.fillna('')\ndf.columns = range(df.columns.size)\ndf\n", - "error_span": null - }, - "dependent_cells": [ - [0, 2], - [0, 3], - [0, 4], - [0, 5], - [0, 6], - [0, 7], - [0, 8], - [0, 9], - [0, 10], - [0, 11], - [0, 12], - [0, 13], - [0, 14], - [0, 15], - [0, 16], - [0, 17], - [0, 18], - [0, 19], - [0, 20], - [0, 21], - [0, 22], - [0, 23], - [0, 24], - [0, 25], - [0, 26], - [0, 27], - [0, 28], - [0, 29], - [0, 30], - [0, 31], - [0, 32], - [0, 33], - [0, 34], - [0, 35], - [0, 36], - [0, 37], - [0, 38], - [0, 39], - [0, 40], - [0, 41], - [0, 42], - [0, 43], - [0, 44], - [0, 45], - [0, 46], - [0, 47], - [0, 48], - [0, 49], - [0, 50], - [0, 51], - [0, 52], - [0, 53], - [0, 54], - [0, 55], - [0, 56], - [0, 57], - [0, 58], - [0, 59], - [0, 60], - [0, 61], - [0, 62], - [0, 63], - [0, 64], - [0, 65], - [0, 66], - [0, 67], - [0, 68], - [0, 69], - [0, 70], - [0, 71], - [0, 72], - [0, 73], - [0, 74], - [0, 75], - [0, 76], - [0, 77], - [0, 78], - [0, 79], - [0, 80], - [0, 81], - [0, 82], - [0, 83], - [0, 84], - [0, 85], - [0, 86], - [0, 87], - [0, 88], - [0, 89], - [0, 90], - [0, 91], - [0, 92], - [0, 93], - [0, 94], - [0, 95], - [0, 96], - [0, 97], - [0, 98], - [0, 99], - [0, 100], - [0, 101], - [0, 102], - [0, 103], - [0, 104], - [0, 105], - [0, 106], - [0, 107], - [0, 108], - [0, 109], - [0, 110], - [0, 111], - [0, 112], - [0, 113], - [0, 114], - [0, 115], - [0, 116], - [0, 117], - [0, 118], - [0, 119], - [0, 120], - [0, 121], - [0, 122], - [0, 123], - [0, 124], - [0, 125], - [0, 126], - [0, 127], - [0, 128], - [0, 129], - [0, 130], - [0, 131], - [0, 132], - [0, 133], - [0, 134], - [0, 135], - [0, 136], - [0, 137], - [0, 138], - [0, 139], - [0, 140], - [0, 141], - [0, 142], - [0, 143], - [0, 144], - [0, 145], - [0, 146], - [0, 147], - [0, 148], - [0, 149], - [0, 150], - [0, 151], - [0, 152], - [0, 153], - [0, 154], - [0, 155], - [0, 156], - [0, 157], - [0, 158], - [0, 159], - [0, 160], - [0, 161], - [0, 162], - [0, 163], - [0, 164], - [0, 165], - [0, 166], - [0, 167], - [0, 168], - [0, 169], - [0, 170], - [0, 171], - [0, 172], - [0, 173], - [0, 174], - [0, 175], - [0, 176], - [0, 177], - [0, 178], - [0, 179], - [0, 180], - [0, 181], - [0, 182], - [0, 183], - [0, 184], - [0, 185], - [0, 186], - [0, 187], - [0, 188], - [0, 189], - [0, 190], - [0, 191], - [0, 192], - [0, 193], - [0, 194], - [0, 195], - [0, 196], - [0, 197], - [0, 198], - [0, 199], - [0, 200], - [0, 201], - [0, 202], - [0, 203], - [0, 204], - [0, 205], - [0, 206], - [0, 207], - [0, 208], - [0, 209], - [0, 210], - [0, 211], - [0, 212], - [0, 213], - [0, 214], - [0, 215], - [0, 216], - [0, 217], - [0, 218], - [0, 219], - [0, 220], - [0, 221], - [0, 222], - [0, 223], - [0, 224], - [0, 225], - [0, 226], - [0, 227], - [0, 228], - [0, 229], - [0, 230], - [0, 231], - [0, 232], - [0, 233], - [0, 234], - [0, 235], - [0, 236], - [0, 237], - [0, 238], - [0, 239], - [0, 240], - [0, 241], - [0, 242], - [0, 243], - [0, 244], - [0, 245], - [0, 246], - [0, 247], - [0, 248], - [0, 249], - [0, 250], - [0, 251], - [0, 252], - [0, 253], - [0, 254], - [0, 255], - [0, 256], - [0, 257], - [0, 258], - [0, 259], - [0, 260], - [0, 261], - [0, 262], - [0, 263], - [0, 264], - [0, 265], - [0, 266], - [0, 267], - [0, 268], - [0, 269], - [0, 270], - [0, 271], - [0, 272], - [0, 273], - [0, 274], - [0, 275], - [0, 276], - [0, 277], - [0, 278], - [0, 279], - [0, 280], - [0, 281], - [0, 282], - [0, 283], - [0, 284], - [0, 285], - [0, 286], - [0, 287], - [0, 288], - [0, 289], - [0, 290], - [0, 291], - [0, 292], - [0, 293], - [0, 294], - [0, 295], - [0, 296], - [0, 297], - [0, 298], - [0, 299], - [0, 300], - [0, 301], - [0, 302], - [0, 303], - [0, 304], - [0, 305], - [0, 306], - [0, 307], - [0, 308], - [0, 309], - [0, 310], - [0, 311], - [0, 312], - [0, 313], - [0, 314], - [0, 315], - [0, 316], - [0, 317], - [0, 318], - [0, 319], - [0, 320], - [0, 321], - [0, 322], - [0, 323], - [0, 324], - [0, 325], - [0, 326], - [0, 327], - [0, 328], - [0, 329], - [0, 330], - [0, 331], - [0, 332], - [0, 333], - [0, 334], - [0, 335], - [0, 336], - [0, 337], - [0, 338], - [0, 339], - [0, 340], - [0, 341], - [0, 342], - [0, 343], - [0, 344], - [0, 345], - [0, 346], - [0, 347], - [0, 348], - [0, 349], - [0, 350], - [0, 351], - [0, 352], - [0, 353], - [0, 354], - [0, 355], - [0, 356], - [0, 357], - [0, 358], - [0, 359], - [0, 360], - [0, 361], - [0, 362], - [0, 363], - [0, 364], - [0, 365], - [0, 366], - [0, 367], - [0, 368], - [0, 369], - [0, 370], - [0, 371], - [0, 372], - [0, 373], - [0, 374], - [0, 375], - [0, 376], - [0, 377], - [0, 378], - [0, 379], - [0, 380], - [0, 381], - [0, 382], - [0, 383], - [0, 384], - [0, 385], - [0, 386], - [0, 387], - [0, 388], - [0, 389], - [0, 390], - [0, 391], - [0, 392], - [0, 393], - [0, 394], - [0, 395], - [0, 396], - [0, 397], - [0, 398], - [0, 399], - [0, 400], - [0, 401], - [0, 402], - [0, 403], - [0, 404], - [0, 405], - [0, 406], - [0, 407], - [0, 408], - [0, 409], - [0, 410], - [0, 411], - [0, 412], - [0, 413], - [0, 414], - [0, 415], - [0, 416], - [0, 417], - [0, 418], - [0, 419], - [0, 420], - [0, 421], - [0, 422], - [0, 423], - [0, 424], - [0, 425], - [0, 426], - [0, 427], - [0, 428], - [0, 429], - [0, 430], - [0, 431], - [0, 432], - [0, 433], - [0, 434], - [0, 435], - [0, 436], - [0, 437], - [0, 438], - [0, 439], - [0, 440], - [0, 441], - [0, 442], - [0, 443], - [0, 444], - [0, 445], - [0, 446], - [0, 447], - [0, 448], - [0, 449], - [0, 450], - [0, 451], - [0, 452], - [0, 453], - [0, 454], - [0, 455], - [0, 456], - [0, 457], - [0, 458], - [0, 459], - [0, 460], - [0, 461], - [0, 462], - [0, 463], - [0, 464], - [0, 465], - [0, 466], - [0, 467], - [0, 468], - [0, 469], - [0, 470], - [0, 471], - [0, 472], - [0, 473], - [0, 474], - [0, 475], - [0, 476], - [0, 477], - [0, 478], - [0, 479], - [0, 480], - [0, 481], - [0, 482], - [0, 483], - [0, 484], - [0, 485], - [0, 486], - [0, 487], - [0, 488], - [0, 489], - [0, 490], - [0, 491], - [0, 492], - [0, 493], - [0, 494], - [0, 495], - [0, 496], - [0, 497], - [0, 498], - [0, 499], - [0, 500], - [1, 2], - [1, 3], - [1, 4], - [1, 5], - [1, 6], - [1, 7], - [1, 8], - [1, 9], - [1, 10], - [1, 11], - [1, 12], - [1, 13], - [1, 14], - [1, 15], - [1, 16], - [1, 17], - [1, 18], - [1, 19], - [1, 20], - [1, 21], - [1, 22], - [1, 23], - [1, 24], - [1, 25], - [1, 26], - [1, 27], - [1, 28], - [1, 29], - [1, 30], - [1, 31], - [1, 32], - [1, 33], - [1, 34], - [1, 35], - [1, 36], - [1, 37], - [1, 38], - [1, 39], - [1, 40], - [1, 41], - [1, 42], - [1, 43], - [1, 44], - [1, 45], - [1, 46], - [1, 47], - [1, 48], - [1, 49], - [1, 50], - [1, 51], - [1, 52], - [1, 53], - [1, 54], - [1, 55], - [1, 56], - [1, 57], - [1, 58], - [1, 59], - [1, 60], - [1, 61], - [1, 62], - [1, 63], - [1, 64], - [1, 65], - [1, 66], - [1, 67], - [1, 68], - [1, 69], - [1, 70], - [1, 71], - [1, 72], - [1, 73], - [1, 74], - [1, 75], - [1, 76], - [1, 77], - [1, 78], - [1, 79], - [1, 80], - [1, 81], - [1, 82], - [1, 83], - [1, 84], - [1, 85], - [1, 86], - [1, 87], - [1, 88], - [1, 89], - [1, 90], - [1, 91], - [1, 92], - [1, 93], - [1, 94], - [1, 95], - [1, 96], - [1, 97], - [1, 98], - [1, 99], - [1, 100], - [1, 101], - [1, 102], - [1, 103], - [1, 104], - [1, 105], - [1, 106], - [1, 107], - [1, 108], - [1, 109], - [1, 110], - [1, 111], - [1, 112], - [1, 113], - [1, 114], - [1, 115], - [1, 116], - [1, 117], - [1, 118], - [1, 119], - [1, 120], - [1, 121], - [1, 122], - [1, 123], - [1, 124], - [1, 125], - [1, 126], - [1, 127], - [1, 128], - [1, 129], - [1, 130], - [1, 131], - [1, 132], - [1, 133], - [1, 134], - [1, 135], - [1, 136], - [1, 137], - [1, 138], - [1, 139], - [1, 140], - [1, 141], - [1, 142], - [1, 143], - [1, 144], - [1, 145], - [1, 146], - [1, 147], - [1, 148], - [1, 149], - [1, 150], - [1, 151], - [1, 152], - [1, 153], - [1, 154], - [1, 155], - [1, 156], - [1, 157], - [1, 158], - [1, 159], - [1, 160], - [1, 161], - [1, 162], - [1, 163], - [1, 164], - [1, 165], - [1, 166], - [1, 167], - [1, 168], - [1, 169], - [1, 170], - [1, 171], - [1, 172], - [1, 173], - [1, 174], - [1, 175], - [1, 176], - [1, 177], - [1, 178], - [1, 179], - [1, 180], - [1, 181], - [1, 182], - [1, 183], - [1, 184], - [1, 185], - [1, 186], - [1, 187], - [1, 188], - [1, 189], - [1, 190], - [1, 191], - [1, 192], - [1, 193], - [1, 194], - [1, 195], - [1, 196], - [1, 197], - [1, 198], - [1, 199], - [1, 200], - [1, 201], - [1, 202], - [1, 203], - [1, 204], - [1, 205], - [1, 206], - [1, 207], - [1, 208], - [1, 209], - [1, 210], - [1, 211], - [1, 212], - [1, 213], - [1, 214], - [1, 215], - [1, 216], - [1, 217], - [1, 218], - [1, 219], - [1, 220], - [1, 221], - [1, 222], - [1, 223], - [1, 224], - [1, 225], - [1, 226], - [1, 227], - [1, 228], - [1, 229], - [1, 230], - [1, 231], - [1, 232], - [1, 233], - [1, 234], - [1, 235], - [1, 236], - [1, 237], - [1, 238], - [1, 239], - [1, 240], - [1, 241], - [1, 242], - [1, 243], - [1, 244], - [1, 245], - [1, 246], - [1, 247], - [1, 248], - [1, 249], - [1, 250], - [1, 251], - [1, 252], - [1, 253], - [1, 254], - [1, 255], - [1, 256], - [1, 257], - [1, 258], - [1, 259], - [1, 260], - [1, 261], - [1, 262], - [1, 263], - [1, 264], - [1, 265], - [1, 266], - [1, 267], - [1, 268], - [1, 269], - [1, 270], - [1, 271], - [1, 272], - [1, 273], - [1, 274], - [1, 275], - [1, 276], - [1, 277], - [1, 278], - [1, 279], - [1, 280], - [1, 281], - [1, 282], - [1, 283], - [1, 284], - [1, 285], - [1, 286], - [1, 287], - [1, 288], - [1, 289], - [1, 290], - [1, 291], - [1, 292], - [1, 293], - [1, 294], - [1, 295], - [1, 296], - [1, 297], - [1, 298], - [1, 299], - [1, 300], - [1, 301], - [1, 302], - [1, 303], - [1, 304], - [1, 305], - [1, 306], - [1, 307], - [1, 308], - [1, 309], - [1, 310], - [1, 311], - [1, 312], - [1, 313], - [1, 314], - [1, 315], - [1, 316], - [1, 317], - [1, 318], - [1, 319], - [1, 320], - [1, 321], - [1, 322], - [1, 323], - [1, 324], - [1, 325], - [1, 326], - [1, 327], - [1, 328], - [1, 329], - [1, 330], - [1, 331], - [1, 332], - [1, 333], - [1, 334], - [1, 335], - [1, 336], - [1, 337], - [1, 338], - [1, 339], - [1, 340], - [1, 341], - [1, 342], - [1, 343], - [1, 344], - [1, 345], - [1, 346], - [1, 347], - [1, 348], - [1, 349], - [1, 350], - [1, 351], - [1, 352], - [1, 353], - [1, 354], - [1, 355], - [1, 356], - [1, 357], - [1, 358], - [1, 359], - [1, 360], - [1, 361], - [1, 362], - [1, 363], - [1, 364], - [1, 365], - [1, 366], - [1, 367], - [1, 368], - [1, 369], - [1, 370], - [1, 371], - [1, 372], - [1, 373], - [1, 374], - [1, 375], - [1, 376], - [1, 377], - [1, 378], - [1, 379], - [1, 380], - [1, 381], - [1, 382], - [1, 383], - [1, 384], - [1, 385], - [1, 386], - [1, 387], - [1, 388], - [1, 389], - [1, 390], - [1, 391], - [1, 392], - [1, 393], - [1, 394], - [1, 395], - [1, 396], - [1, 397], - [1, 398], - [1, 399], - [1, 400], - [1, 401], - [1, 402], - [1, 403], - [1, 404], - [1, 405], - [1, 406], - [1, 407], - [1, 408], - [1, 409], - [1, 410], - [1, 411], - [1, 412], - [1, 413], - [1, 414], - [1, 415], - [1, 416], - [1, 417], - [1, 418], - [1, 419], - [1, 420], - [1, 421], - [1, 422], - [1, 423], - [1, 424], - [1, 425], - [1, 426], - [1, 427], - [1, 428], - [1, 429], - [1, 430], - [1, 431], - [1, 432], - [1, 433], - [1, 434], - [1, 435], - [1, 436], - [1, 437], - [1, 438], - [1, 439], - [1, 440], - [1, 441], - [1, 442], - [1, 443], - [1, 444], - [1, 445], - [1, 446], - [1, 447], - [1, 448], - [1, 449], - [1, 450], - [1, 451], - [1, 452], - [1, 453], - [1, 454], - [1, 455], - [1, 456], - [1, 457], - [1, 458], - [1, 459], - [1, 460], - [1, 461], - [1, 462], - [1, 463], - [1, 464], - [1, 465], - [1, 466], - [1, 467], - [1, 468], - [1, 469], - [1, 470], - [1, 471], - [1, 472], - [1, 473], - [1, 474], - [1, 475], - [1, 476], - [1, 477], - [1, 478], - [1, 479], - [1, 480], - [1, 481], - [1, 482], - [1, 483], - [1, 484], - [1, 485], - [1, 486], - [1, 487], - [1, 488], - [1, 489], - [1, 490], - [1, 491], - [1, 492], - [1, 493], - [1, 494], - [1, 495], - [1, 496], - [1, 497], - [1, 498], - [1, 499], - [1, 500], - [2, 2], - [2, 3], - [2, 4], - [2, 5], - [2, 6], - [2, 7], - [2, 8], - [2, 9], - [2, 10], - [2, 11], - [2, 12], - [2, 13], - [2, 14], - [2, 15], - [2, 16], - [2, 17], - [2, 18], - [2, 19], - [2, 20], - [2, 21], - [2, 22], - [2, 23], - [2, 24], - [2, 25], - [2, 26], - [2, 27], - [2, 28], - [2, 29], - [2, 30], - [2, 31], - [2, 32], - [2, 33], - [2, 34], - [2, 35], - [2, 36], - [2, 37], - [2, 38], - [2, 39], - [2, 40], - [2, 41], - [2, 42], - [2, 43], - [2, 44], - [2, 45], - [2, 46], - [2, 47], - [2, 48], - [2, 49], - [2, 50], - [2, 51], - [2, 52], - [2, 53], - [2, 54], - [2, 55], - [2, 56], - [2, 57], - [2, 58], - [2, 59], - [2, 60], - [2, 61], - [2, 62], - [2, 63], - [2, 64], - [2, 65], - [2, 66], - [2, 67], - [2, 68], - [2, 69], - [2, 70], - [2, 71], - [2, 72], - [2, 73], - [2, 74], - [2, 75], - [2, 76], - [2, 77], - [2, 78], - [2, 79], - [2, 80], - [2, 81], - [2, 82], - [2, 83], - [2, 84], - [2, 85], - [2, 86], - [2, 87], - [2, 88], - [2, 89], - [2, 90], - [2, 91], - [2, 92], - [2, 93], - [2, 94], - [2, 95], - [2, 96], - [2, 97], - [2, 98], - [2, 99], - [2, 100], - [2, 101], - [2, 102], - [2, 103], - [2, 104], - [2, 105], - [2, 106], - [2, 107], - [2, 108], - [2, 109], - [2, 110], - [2, 111], - [2, 112], - [2, 113], - [2, 114], - [2, 115], - [2, 116], - [2, 117], - [2, 118], - [2, 119], - [2, 120], - [2, 121], - [2, 122], - [2, 123], - [2, 124], - [2, 125], - [2, 126], - [2, 127], - [2, 128], - [2, 129], - [2, 130], - [2, 131], - [2, 132], - [2, 133], - [2, 134], - [2, 135], - [2, 136], - [2, 137], - [2, 138], - [2, 139], - [2, 140], - [2, 141], - [2, 142], - [2, 143], - [2, 144], - [2, 145], - [2, 146], - [2, 147], - [2, 148], - [2, 149], - [2, 150], - [2, 151], - [2, 152], - [2, 153], - [2, 154], - [2, 155], - [2, 156], - [2, 157], - [2, 158], - [2, 159], - [2, 160], - [2, 161], - [2, 162], - [2, 163], - [2, 164], - [2, 165], - [2, 166], - [2, 167], - [2, 168], - [2, 169], - [2, 170], - [2, 171], - [2, 172], - [2, 173], - [2, 174], - [2, 175], - [2, 176], - [2, 177], - [2, 178], - [2, 179], - [2, 180], - [2, 181], - [2, 182], - [2, 183], - [2, 184], - [2, 185], - [2, 186], - [2, 187], - [2, 188], - [2, 189], - [2, 190], - [2, 191], - [2, 192], - [2, 193], - [2, 194], - [2, 195], - [2, 196], - [2, 197], - [2, 198], - [2, 199], - [2, 200], - [2, 201], - [2, 202], - [2, 203], - [2, 204], - [2, 205], - [2, 206], - [2, 207], - [2, 208], - [2, 209], - [2, 210], - [2, 211], - [2, 212], - [2, 213], - [2, 214], - [2, 215], - [2, 216], - [2, 217], - [2, 218], - [2, 219], - [2, 220], - [2, 221], - [2, 222], - [2, 223], - [2, 224], - [2, 225], - [2, 226], - [2, 227], - [2, 228], - [2, 229], - [2, 230], - [2, 231], - [2, 232], - [2, 233], - [2, 234], - [2, 235], - [2, 236], - [2, 237], - [2, 238], - [2, 239], - [2, 240], - [2, 241], - [2, 242], - [2, 243], - [2, 244], - [2, 245], - [2, 246], - [2, 247], - [2, 248], - [2, 249], - [2, 250], - [2, 251], - [2, 252], - [2, 253], - [2, 254], - [2, 255], - [2, 256], - [2, 257], - [2, 258], - [2, 259], - [2, 260], - [2, 261], - [2, 262], - [2, 263], - [2, 264], - [2, 265], - [2, 266], - [2, 267], - [2, 268], - [2, 269], - [2, 270], - [2, 271], - [2, 272], - [2, 273], - [2, 274], - [2, 275], - [2, 276], - [2, 277], - [2, 278], - [2, 279], - [2, 280], - [2, 281], - [2, 282], - [2, 283], - [2, 284], - [2, 285], - [2, 286], - [2, 287], - [2, 288], - [2, 289], - [2, 290], - [2, 291], - [2, 292], - [2, 293], - [2, 294], - [2, 295], - [2, 296], - [2, 297], - [2, 298], - [2, 299], - [2, 300], - [2, 301], - [2, 302], - [2, 303], - [2, 304], - [2, 305], - [2, 306], - [2, 307], - [2, 308], - [2, 309], - [2, 310], - [2, 311], - [2, 312], - [2, 313], - [2, 314], - [2, 315], - [2, 316], - [2, 317], - [2, 318], - [2, 319], - [2, 320], - [2, 321], - [2, 322], - [2, 323], - [2, 324], - [2, 325], - [2, 326], - [2, 327], - [2, 328], - [2, 329], - [2, 330], - [2, 331], - [2, 332], - [2, 333], - [2, 334], - [2, 335], - [2, 336], - [2, 337], - [2, 338], - [2, 339], - [2, 340], - [2, 341], - [2, 342], - [2, 343], - [2, 344], - [2, 345], - [2, 346], - [2, 347], - [2, 348], - [2, 349], - [2, 350], - [2, 351], - [2, 352], - [2, 353], - [2, 354], - [2, 355], - [2, 356], - [2, 357], - [2, 358], - [2, 359], - [2, 360], - [2, 361], - [2, 362], - [2, 363], - [2, 364], - [2, 365], - [2, 366], - [2, 367], - [2, 368], - [2, 369], - [2, 370], - [2, 371], - [2, 372], - [2, 373], - [2, 374], - [2, 375], - [2, 376], - [2, 377], - [2, 378], - [2, 379], - [2, 380], - [2, 381], - [2, 382], - [2, 383], - [2, 384], - [2, 385], - [2, 386], - [2, 387], - [2, 388], - [2, 389], - [2, 390], - [2, 391], - [2, 392], - [2, 393], - [2, 394], - [2, 395], - [2, 396], - [2, 397], - [2, 398], - [2, 399], - [2, 400], - [2, 401], - [2, 402], - [2, 403], - [2, 404], - [2, 405], - [2, 406], - [2, 407], - [2, 408], - [2, 409], - [2, 410], - [2, 411], - [2, 412], - [2, 413], - [2, 414], - [2, 415], - [2, 416], - [2, 417], - [2, 418], - [2, 419], - [2, 420], - [2, 421], - [2, 422], - [2, 423], - [2, 424], - [2, 425], - [2, 426], - [2, 427], - [2, 428], - [2, 429], - [2, 430], - [2, 431], - [2, 432], - [2, 433], - [2, 434], - [2, 435], - [2, 436], - [2, 437], - [2, 438], - [2, 439], - [2, 440], - [2, 441], - [2, 442], - [2, 443], - [2, 444], - [2, 445], - [2, 446], - [2, 447], - [2, 448], - [2, 449], - [2, 450], - [2, 451], - [2, 452], - [2, 453], - [2, 454], - [2, 455], - [2, 456], - [2, 457], - [2, 458], - [2, 459], - [2, 460], - [2, 461], - [2, 462], - [2, 463], - [2, 464], - [2, 465], - [2, 466], - [2, 467], - [2, 468], - [2, 469], - [2, 470], - [2, 471], - [2, 472], - [2, 473], - [2, 474], - [2, 475], - [2, 476], - [2, 477], - [2, 478], - [2, 479], - [2, 480], - [2, 481], - [2, 482], - [2, 483], - [2, 484], - [2, 485], - [2, 486], - [2, 487], - [2, 488], - [2, 489], - [2, 490], - [2, 491], - [2, 492], - [2, 493], - [2, 494], - [2, 495], - [2, 496], - [2, 497], - [2, 498], - [2, 499], - [2, 500], - [3, 2], - [3, 3], - [3, 4], - [3, 5], - [3, 6], - [3, 7], - [3, 8], - [3, 9], - [3, 10], - [3, 11], - [3, 12], - [3, 13], - [3, 14], - [3, 15], - [3, 16], - [3, 17], - [3, 18], - [3, 19], - [3, 20], - [3, 21], - [3, 22], - [3, 23], - [3, 24], - [3, 25], - [3, 26], - [3, 27], - [3, 28], - [3, 29], - [3, 30], - [3, 31], - [3, 32], - [3, 33], - [3, 34], - [3, 35], - [3, 36], - [3, 37], - [3, 38], - [3, 39], - [3, 40], - [3, 41], - [3, 42], - [3, 43], - [3, 44], - [3, 45], - [3, 46], - [3, 47], - [3, 48], - [3, 49], - [3, 50], - [3, 51], - [3, 52], - [3, 53], - [3, 54], - [3, 55], - [3, 56], - [3, 57], - [3, 58], - [3, 59], - [3, 60], - [3, 61], - [3, 62], - [3, 63], - [3, 64], - [3, 65], - [3, 66], - [3, 67], - [3, 68], - [3, 69], - [3, 70], - [3, 71], - [3, 72], - [3, 73], - [3, 74], - [3, 75], - [3, 76], - [3, 77], - [3, 78], - [3, 79], - [3, 80], - [3, 81], - [3, 82], - [3, 83], - [3, 84], - [3, 85], - [3, 86], - [3, 87], - [3, 88], - [3, 89], - [3, 90], - [3, 91], - [3, 92], - [3, 93], - [3, 94], - [3, 95], - [3, 96], - [3, 97], - [3, 98], - [3, 99], - [3, 100], - [3, 101], - [3, 102], - [3, 103], - [3, 104], - [3, 105], - [3, 106], - [3, 107], - [3, 108], - [3, 109], - [3, 110], - [3, 111], - [3, 112], - [3, 113], - [3, 114], - [3, 115], - [3, 116], - [3, 117], - [3, 118], - [3, 119], - [3, 120], - [3, 121], - [3, 122], - [3, 123], - [3, 124], - [3, 125], - [3, 126], - [3, 127], - [3, 128], - [3, 129], - [3, 130], - [3, 131], - [3, 132], - [3, 133], - [3, 134], - [3, 135], - [3, 136], - [3, 137], - [3, 138], - [3, 139], - [3, 140], - [3, 141], - [3, 142], - [3, 143], - [3, 144], - [3, 145], - [3, 146], - [3, 147], - [3, 148], - [3, 149], - [3, 150], - [3, 151], - [3, 152], - [3, 153], - [3, 154], - [3, 155], - [3, 156], - [3, 157], - [3, 158], - [3, 159], - [3, 160], - [3, 161], - [3, 162], - [3, 163], - [3, 164], - [3, 165], - [3, 166], - [3, 167], - [3, 168], - [3, 169], - [3, 170], - [3, 171], - [3, 172], - [3, 173], - [3, 174], - [3, 175], - [3, 176], - [3, 177], - [3, 178], - [3, 179], - [3, 180], - [3, 181], - [3, 182], - [3, 183], - [3, 184], - [3, 185], - [3, 186], - [3, 187], - [3, 188], - [3, 189], - [3, 190], - [3, 191], - [3, 192], - [3, 193], - [3, 194], - [3, 195], - [3, 196], - [3, 197], - [3, 198], - [3, 199], - [3, 200], - [3, 201], - [3, 202], - [3, 203], - [3, 204], - [3, 205], - [3, 206], - [3, 207], - [3, 208], - [3, 209], - [3, 210], - [3, 211], - [3, 212], - [3, 213], - [3, 214], - [3, 215], - [3, 216], - [3, 217], - [3, 218], - [3, 219], - [3, 220], - [3, 221], - [3, 222], - [3, 223], - [3, 224], - [3, 225], - [3, 226], - [3, 227], - [3, 228], - [3, 229], - [3, 230], - [3, 231], - [3, 232], - [3, 233], - [3, 234], - [3, 235], - [3, 236], - [3, 237], - [3, 238], - [3, 239], - [3, 240], - [3, 241], - [3, 242], - [3, 243], - [3, 244], - [3, 245], - [3, 246], - [3, 247], - [3, 248], - [3, 249], - [3, 250], - [3, 251], - [3, 252], - [3, 253], - [3, 254], - [3, 255], - [3, 256], - [3, 257], - [3, 258], - [3, 259], - [3, 260], - [3, 261], - [3, 262], - [3, 263], - [3, 264], - [3, 265], - [3, 266], - [3, 267], - [3, 268], - [3, 269], - [3, 270], - [3, 271], - [3, 272], - [3, 273], - [3, 274], - [3, 275], - [3, 276], - [3, 277], - [3, 278], - [3, 279], - [3, 280], - [3, 281], - [3, 282], - [3, 283], - [3, 284], - [3, 285], - [3, 286], - [3, 287], - [3, 288], - [3, 289], - [3, 290], - [3, 291], - [3, 292], - [3, 293], - [3, 294], - [3, 295], - [3, 296], - [3, 297], - [3, 298], - [3, 299], - [3, 300], - [3, 301], - [3, 302], - [3, 303], - [3, 304], - [3, 305], - [3, 306], - [3, 307], - [3, 308], - [3, 309], - [3, 310], - [3, 311], - [3, 312], - [3, 313], - [3, 314], - [3, 315], - [3, 316], - [3, 317], - [3, 318], - [3, 319], - [3, 320], - [3, 321], - [3, 322], - [3, 323], - [3, 324], - [3, 325], - [3, 326], - [3, 327], - [3, 328], - [3, 329], - [3, 330], - [3, 331], - [3, 332], - [3, 333], - [3, 334], - [3, 335], - [3, 336], - [3, 337], - [3, 338], - [3, 339], - [3, 340], - [3, 341], - [3, 342], - [3, 343], - [3, 344], - [3, 345], - [3, 346], - [3, 347], - [3, 348], - [3, 349], - [3, 350], - [3, 351], - [3, 352], - [3, 353], - [3, 354], - [3, 355], - [3, 356], - [3, 357], - [3, 358], - [3, 359], - [3, 360], - [3, 361], - [3, 362], - [3, 363], - [3, 364], - [3, 365], - [3, 366], - [3, 367], - [3, 368], - [3, 369], - [3, 370], - [3, 371], - [3, 372], - [3, 373], - [3, 374], - [3, 375], - [3, 376], - [3, 377], - [3, 378], - [3, 379], - [3, 380], - [3, 381], - [3, 382], - [3, 383], - [3, 384], - [3, 385], - [3, 386], - [3, 387], - [3, 388], - [3, 389], - [3, 390], - [3, 391], - [3, 392], - [3, 393], - [3, 394], - [3, 395], - [3, 396], - [3, 397], - [3, 398], - [3, 399], - [3, 400], - [3, 401], - [3, 402], - [3, 403], - [3, 404], - [3, 405], - [3, 406], - [3, 407], - [3, 408], - [3, 409], - [3, 410], - [3, 411], - [3, 412], - [3, 413], - [3, 414], - [3, 415], - [3, 416], - [3, 417], - [3, 418], - [3, 419], - [3, 420], - [3, 421], - [3, 422], - [3, 423], - [3, 424], - [3, 425], - [3, 426], - [3, 427], - [3, 428], - [3, 429], - [3, 430], - [3, 431], - [3, 432], - [3, 433], - [3, 434], - [3, 435], - [3, 436], - [3, 437], - [3, 438], - [3, 439], - [3, 440], - [3, 441], - [3, 442], - [3, 443], - [3, 444], - [3, 445], - [3, 446], - [3, 447], - [3, 448], - [3, 449], - [3, 450], - [3, 451], - [3, 452], - [3, 453], - [3, 454], - [3, 455], - [3, 456], - [3, 457], - [3, 458], - [3, 459], - [3, 460], - [3, 461], - [3, 462], - [3, 463], - [3, 464], - [3, 465], - [3, 466], - [3, 467], - [3, 468], - [3, 469], - [3, 470], - [3, 471], - [3, 472], - [3, 473], - [3, 474], - [3, 475], - [3, 476], - [3, 477], - [3, 478], - [3, 479], - [3, 480], - [3, 481], - [3, 482], - [3, 483], - [3, 484], - [3, 485], - [3, 486], - [3, 487], - [3, 488], - [3, 489], - [3, 490], - [3, 491], - [3, 492], - [3, 493], - [3, 494], - [3, 495], - [3, 496], - [3, 497], - [3, 498], - [3, 499], - [3, 500], - [4, 2], - [4, 3], - [4, 4], - [4, 5], - [4, 6], - [4, 7], - [4, 8], - [4, 9], - [4, 10], - [4, 11], - [4, 12], - [4, 13], - [4, 14], - [4, 15], - [4, 16], - [4, 17], - [4, 18], - [4, 19], - [4, 20], - [4, 21], - [4, 22], - [4, 23], - [4, 24], - [4, 25], - [4, 26], - [4, 27], - [4, 28], - [4, 29], - [4, 30], - [4, 31], - [4, 32], - [4, 33], - [4, 34], - [4, 35], - [4, 36], - [4, 37], - [4, 38], - [4, 39], - [4, 40], - [4, 41], - [4, 42], - [4, 43], - [4, 44], - [4, 45], - [4, 46], - [4, 47], - [4, 48], - [4, 49], - [4, 50], - [4, 51], - [4, 52], - [4, 53], - [4, 54], - [4, 55], - [4, 56], - [4, 57], - [4, 58], - [4, 59], - [4, 60], - [4, 61], - [4, 62], - [4, 63], - [4, 64], - [4, 65], - [4, 66], - [4, 67], - [4, 68], - [4, 69], - [4, 70], - [4, 71], - [4, 72], - [4, 73], - [4, 74], - [4, 75], - [4, 76], - [4, 77], - [4, 78], - [4, 79], - [4, 80], - [4, 81], - [4, 82], - [4, 83], - [4, 84], - [4, 85], - [4, 86], - [4, 87], - [4, 88], - [4, 89], - [4, 90], - [4, 91], - [4, 92], - [4, 93], - [4, 94], - [4, 95], - [4, 96], - [4, 97], - [4, 98], - [4, 99], - [4, 100], - [4, 101], - [4, 102], - [4, 103], - [4, 104], - [4, 105], - [4, 106], - [4, 107], - [4, 108], - [4, 109], - [4, 110], - [4, 111], - [4, 112], - [4, 113], - [4, 114], - [4, 115], - [4, 116], - [4, 117], - [4, 118], - [4, 119], - [4, 120], - [4, 121], - [4, 122], - [4, 123], - [4, 124], - [4, 125], - [4, 126], - [4, 127], - [4, 128], - [4, 129], - [4, 130], - [4, 131], - [4, 132], - [4, 133], - [4, 134], - [4, 135], - [4, 136], - [4, 137], - [4, 138], - [4, 139], - [4, 140], - [4, 141], - [4, 142], - [4, 143], - [4, 144], - [4, 145], - [4, 146], - [4, 147], - [4, 148], - [4, 149], - [4, 150], - [4, 151], - [4, 152], - [4, 153], - [4, 154], - [4, 155], - [4, 156], - [4, 157], - [4, 158], - [4, 159], - [4, 160], - [4, 161], - [4, 162], - [4, 163], - [4, 164], - [4, 165], - [4, 166], - [4, 167], - [4, 168], - [4, 169], - [4, 170], - [4, 171], - [4, 172], - [4, 173], - [4, 174], - [4, 175], - [4, 176], - [4, 177], - [4, 178], - [4, 179], - [4, 180], - [4, 181], - [4, 182], - [4, 183], - [4, 184], - [4, 185], - [4, 186], - [4, 187], - [4, 188], - [4, 189], - [4, 190], - [4, 191], - [4, 192], - [4, 193], - [4, 194], - [4, 195], - [4, 196], - [4, 197], - [4, 198], - [4, 199], - [4, 200], - [4, 201], - [4, 202], - [4, 203], - [4, 204], - [4, 205], - [4, 206], - [4, 207], - [4, 208], - [4, 209], - [4, 210], - [4, 211], - [4, 212], - [4, 213], - [4, 214], - [4, 215], - [4, 216], - [4, 217], - [4, 218], - [4, 219], - [4, 220], - [4, 221], - [4, 222], - [4, 223], - [4, 224], - [4, 225], - [4, 226], - [4, 227], - [4, 228], - [4, 229], - [4, 230], - [4, 231], - [4, 232], - [4, 233], - [4, 234], - [4, 235], - [4, 236], - [4, 237], - [4, 238], - [4, 239], - [4, 240], - [4, 241], - [4, 242], - [4, 243], - [4, 244], - [4, 245], - [4, 246], - [4, 247], - [4, 248], - [4, 249], - [4, 250], - [4, 251], - [4, 252], - [4, 253], - [4, 254], - [4, 255], - [4, 256], - [4, 257], - [4, 258], - [4, 259], - [4, 260], - [4, 261], - [4, 262], - [4, 263], - [4, 264], - [4, 265], - [4, 266], - [4, 267], - [4, 268], - [4, 269], - [4, 270], - [4, 271], - [4, 272], - [4, 273], - [4, 274], - [4, 275], - [4, 276], - [4, 277], - [4, 278], - [4, 279], - [4, 280], - [4, 281], - [4, 282], - [4, 283], - [4, 284], - [4, 285], - [4, 286], - [4, 287], - [4, 288], - [4, 289], - [4, 290], - [4, 291], - [4, 292], - [4, 293], - [4, 294], - [4, 295], - [4, 296], - [4, 297], - [4, 298], - [4, 299], - [4, 300], - [4, 301], - [4, 302], - [4, 303], - [4, 304], - [4, 305], - [4, 306], - [4, 307], - [4, 308], - [4, 309], - [4, 310], - [4, 311], - [4, 312], - [4, 313], - [4, 314], - [4, 315], - [4, 316], - [4, 317], - [4, 318], - [4, 319], - [4, 320], - [4, 321], - [4, 322], - [4, 323], - [4, 324], - [4, 325], - [4, 326], - [4, 327], - [4, 328], - [4, 329], - [4, 330], - [4, 331], - [4, 332], - [4, 333], - [4, 334], - [4, 335], - [4, 336], - [4, 337], - [4, 338], - [4, 339], - [4, 340], - [4, 341], - [4, 342], - [4, 343], - [4, 344], - [4, 345], - [4, 346], - [4, 347], - [4, 348], - [4, 349], - [4, 350], - [4, 351], - [4, 352], - [4, 353], - [4, 354], - [4, 355], - [4, 356], - [4, 357], - [4, 358], - [4, 359], - [4, 360], - [4, 361], - [4, 362], - [4, 363], - [4, 364], - [4, 365], - [4, 366], - [4, 367], - [4, 368], - [4, 369], - [4, 370], - [4, 371], - [4, 372], - [4, 373], - [4, 374], - [4, 375], - [4, 376], - [4, 377], - [4, 378], - [4, 379], - [4, 380], - [4, 381], - [4, 382], - [4, 383], - [4, 384], - [4, 385], - [4, 386], - [4, 387], - [4, 388], - [4, 389], - [4, 390], - [4, 391], - [4, 392], - [4, 393], - [4, 394], - [4, 395], - [4, 396], - [4, 397], - [4, 398], - [4, 399], - [4, 400], - [4, 401], - [4, 402], - [4, 403], - [4, 404], - [4, 405], - [4, 406], - [4, 407], - [4, 408], - [4, 409], - [4, 410], - [4, 411], - [4, 412], - [4, 413], - [4, 414], - [4, 415], - [4, 416], - [4, 417], - [4, 418], - [4, 419], - [4, 420], - [4, 421], - [4, 422], - [4, 423], - [4, 424], - [4, 425], - [4, 426], - [4, 427], - [4, 428], - [4, 429], - [4, 430], - [4, 431], - [4, 432], - [4, 433], - [4, 434], - [4, 435], - [4, 436], - [4, 437], - [4, 438], - [4, 439], - [4, 440], - [4, 441], - [4, 442], - [4, 443], - [4, 444], - [4, 445], - [4, 446], - [4, 447], - [4, 448], - [4, 449], - [4, 450], - [4, 451], - [4, 452], - [4, 453], - [4, 454], - [4, 455], - [4, 456], - [4, 457], - [4, 458], - [4, 459], - [4, 460], - [4, 461], - [4, 462], - [4, 463], - [4, 464], - [4, 465], - [4, 466], - [4, 467], - [4, 468], - [4, 469], - [4, 470], - [4, 471], - [4, 472], - [4, 473], - [4, 474], - [4, 475], - [4, 476], - [4, 477], - [4, 478], - [4, 479], - [4, 480], - [4, 481], - [4, 482], - [4, 483], - [4, 484], - [4, 485], - [4, 486], - [4, 487], - [4, 488], - [4, 489], - [4, 490], - [4, 491], - [4, 492], - [4, 493], - [4, 494], - [4, 495], - [4, 496], - [4, 497], - [4, 498], - [4, 499], - [4, 500], - [5, 2], - [5, 3], - [5, 4], - [5, 5], - [5, 6], - [5, 7], - [5, 8], - [5, 9], - [5, 10], - [5, 11], - [5, 12], - [5, 13], - [5, 14], - [5, 15], - [5, 16], - [5, 17], - [5, 18], - [5, 19], - [5, 20], - [5, 21], - [5, 22], - [5, 23], - [5, 24], - [5, 25], - [5, 26], - [5, 27], - [5, 28], - [5, 29], - [5, 30], - [5, 31], - [5, 32], - [5, 33], - [5, 34], - [5, 35], - [5, 36], - [5, 37], - [5, 38], - [5, 39], - [5, 40], - [5, 41], - [5, 42], - [5, 43], - [5, 44], - [5, 45], - [5, 46], - [5, 47], - [5, 48], - [5, 49], - [5, 50], - [5, 51], - [5, 52], - [5, 53], - [5, 54], - [5, 55], - [5, 56], - [5, 57], - [5, 58], - [5, 59], - [5, 60], - [5, 61], - [5, 62], - [5, 63], - [5, 64], - [5, 65], - [5, 66], - [5, 67], - [5, 68], - [5, 69], - [5, 70], - [5, 71], - [5, 72], - [5, 73], - [5, 74], - [5, 75], - [5, 76], - [5, 77], - [5, 78], - [5, 79], - [5, 80], - [5, 81], - [5, 82], - [5, 83], - [5, 84], - [5, 85], - [5, 86], - [5, 87], - [5, 88], - [5, 89], - [5, 90], - [5, 91], - [5, 92], - [5, 93], - [5, 94], - [5, 95], - [5, 96], - [5, 97], - [5, 98], - [5, 99], - [5, 100], - [5, 101], - [5, 102], - [5, 103], - [5, 104], - [5, 105], - [5, 106], - [5, 107], - [5, 108], - [5, 109], - [5, 110], - [5, 111], - [5, 112], - [5, 113], - [5, 114], - [5, 115], - [5, 116], - [5, 117], - [5, 118], - [5, 119], - [5, 120], - [5, 121], - [5, 122], - [5, 123], - [5, 124], - [5, 125], - [5, 126], - [5, 127], - [5, 128], - [5, 129], - [5, 130], - [5, 131], - [5, 132], - [5, 133], - [5, 134], - [5, 135], - [5, 136], - [5, 137], - [5, 138], - [5, 139], - [5, 140], - [5, 141], - [5, 142], - [5, 143], - [5, 144], - [5, 145], - [5, 146], - [5, 147], - [5, 148], - [5, 149], - [5, 150], - [5, 151], - [5, 152], - [5, 153], - [5, 154], - [5, 155], - [5, 156], - [5, 157], - [5, 158], - [5, 159], - [5, 160], - [5, 161], - [5, 162], - [5, 163], - [5, 164], - [5, 165], - [5, 166], - [5, 167], - [5, 168], - [5, 169], - [5, 170], - [5, 171], - [5, 172], - [5, 173], - [5, 174], - [5, 175], - [5, 176], - [5, 177], - [5, 178], - [5, 179], - [5, 180], - [5, 181], - [5, 182], - [5, 183], - [5, 184], - [5, 185], - [5, 186], - [5, 187], - [5, 188], - [5, 189], - [5, 190], - [5, 191], - [5, 192], - [5, 193], - [5, 194], - [5, 195], - [5, 196], - [5, 197], - [5, 198], - [5, 199], - [5, 200], - [5, 201], - [5, 202], - [5, 203], - [5, 204], - [5, 205], - [5, 206], - [5, 207], - [5, 208], - [5, 209], - [5, 210], - [5, 211], - [5, 212], - [5, 213], - [5, 214], - [5, 215], - [5, 216], - [5, 217], - [5, 218], - [5, 219], - [5, 220], - [5, 221], - [5, 222], - [5, 223], - [5, 224], - [5, 225], - [5, 226], - [5, 227], - [5, 228], - [5, 229], - [5, 230], - [5, 231], - [5, 232], - [5, 233], - [5, 234], - [5, 235], - [5, 236], - [5, 237], - [5, 238], - [5, 239], - [5, 240], - [5, 241], - [5, 242], - [5, 243], - [5, 244], - [5, 245], - [5, 246], - [5, 247], - [5, 248], - [5, 249], - [5, 250], - [5, 251], - [5, 252], - [5, 253], - [5, 254], - [5, 255], - [5, 256], - [5, 257], - [5, 258], - [5, 259], - [5, 260], - [5, 261], - [5, 262], - [5, 263], - [5, 264], - [5, 265], - [5, 266], - [5, 267], - [5, 268], - [5, 269], - [5, 270], - [5, 271], - [5, 272], - [5, 273], - [5, 274], - [5, 275], - [5, 276], - [5, 277], - [5, 278], - [5, 279], - [5, 280], - [5, 281], - [5, 282], - [5, 283], - [5, 284], - [5, 285], - [5, 286], - [5, 287], - [5, 288], - [5, 289], - [5, 290], - [5, 291], - [5, 292], - [5, 293], - [5, 294], - [5, 295], - [5, 296], - [5, 297], - [5, 298], - [5, 299], - [5, 300], - [5, 301], - [5, 302], - [5, 303], - [5, 304], - [5, 305], - [5, 306], - [5, 307], - [5, 308], - [5, 309], - [5, 310], - [5, 311], - [5, 312], - [5, 313], - [5, 314], - [5, 315], - [5, 316], - [5, 317], - [5, 318], - [5, 319], - [5, 320], - [5, 321], - [5, 322], - [5, 323], - [5, 324], - [5, 325], - [5, 326], - [5, 327], - [5, 328], - [5, 329], - [5, 330], - [5, 331], - [5, 332], - [5, 333], - [5, 334], - [5, 335], - [5, 336], - [5, 337], - [5, 338], - [5, 339], - [5, 340], - [5, 341], - [5, 342], - [5, 343], - [5, 344], - [5, 345], - [5, 346], - [5, 347], - [5, 348], - [5, 349], - [5, 350], - [5, 351], - [5, 352], - [5, 353], - [5, 354], - [5, 355], - [5, 356], - [5, 357], - [5, 358], - [5, 359], - [5, 360], - [5, 361], - [5, 362], - [5, 363], - [5, 364], - [5, 365], - [5, 366], - [5, 367], - [5, 368], - [5, 369], - [5, 370], - [5, 371], - [5, 372], - [5, 373], - [5, 374], - [5, 375], - [5, 376], - [5, 377], - [5, 378], - [5, 379], - [5, 380], - [5, 381], - [5, 382], - [5, 383], - [5, 384], - [5, 385], - [5, 386], - [5, 387], - [5, 388], - [5, 389], - [5, 390], - [5, 391], - [5, 392], - [5, 393], - [5, 394], - [5, 395], - [5, 396], - [5, 397], - [5, 398], - [5, 399], - [5, 400], - [5, 401], - [5, 402], - [5, 403], - [5, 404], - [5, 405], - [5, 406], - [5, 407], - [5, 408], - [5, 409], - [5, 410], - [5, 411], - [5, 412], - [5, 413], - [5, 414], - [5, 415], - [5, 416], - [5, 417], - [5, 418], - [5, 419], - [5, 420], - [5, 421], - [5, 422], - [5, 423], - [5, 424], - [5, 425], - [5, 426], - [5, 427], - [5, 428], - [5, 429], - [5, 430], - [5, 431], - [5, 432], - [5, 433], - [5, 434], - [5, 435], - [5, 436], - [5, 437], - [5, 438], - [5, 439], - [5, 440], - [5, 441], - [5, 442], - [5, 443], - [5, 444], - [5, 445], - [5, 446], - [5, 447], - [5, 448], - [5, 449], - [5, 450], - [5, 451], - [5, 452], - [5, 453], - [5, 454], - [5, 455], - [5, 456], - [5, 457], - [5, 458], - [5, 459], - [5, 460], - [5, 461], - [5, 462], - [5, 463], - [5, 464], - [5, 465], - [5, 466], - [5, 467], - [5, 468], - [5, 469], - [5, 470], - [5, 471], - [5, 472], - [5, 473], - [5, 474], - [5, 475], - [5, 476], - [5, 477], - [5, 478], - [5, 479], - [5, 480], - [5, 481], - [5, 482], - [5, 483], - [5, 484], - [5, 485], - [5, 486], - [5, 487], - [5, 488], - [5, 489], - [5, 490], - [5, 491], - [5, 492], - [5, 493], - [5, 494], - [5, 495], - [5, 496], - [5, 497], - [5, 498], - [5, 499], - [5, 500], - [6, 2], - [6, 3], - [6, 4], - [6, 5], - [6, 6], - [6, 7], - [6, 8], - [6, 9], - [6, 10], - [6, 11], - [6, 12], - [6, 13], - [6, 14], - [6, 15], - [6, 16], - [6, 17], - [6, 18], - [6, 19], - [6, 20], - [6, 21], - [6, 22], - [6, 23], - [6, 24], - [6, 25], - [6, 26], - [6, 27], - [6, 28], - [6, 29], - [6, 30], - [6, 31], - [6, 32], - [6, 33], - [6, 34], - [6, 35], - [6, 36], - [6, 37], - [6, 38], - [6, 39], - [6, 40], - [6, 41], - [6, 42], - [6, 43], - [6, 44], - [6, 45], - [6, 46], - [6, 47], - [6, 48], - [6, 49], - [6, 50], - [6, 51], - [6, 52], - [6, 53], - [6, 54], - [6, 55], - [6, 56], - [6, 57], - [6, 58], - [6, 59], - [6, 60], - [6, 61], - [6, 62], - [6, 63], - [6, 64], - [6, 65], - [6, 66], - [6, 67], - [6, 68], - [6, 69], - [6, 70], - [6, 71], - [6, 72], - [6, 73], - [6, 74], - [6, 75], - [6, 76], - [6, 77], - [6, 78], - [6, 79], - [6, 80], - [6, 81], - [6, 82], - [6, 83], - [6, 84], - [6, 85], - [6, 86], - [6, 87], - [6, 88], - [6, 89], - [6, 90], - [6, 91], - [6, 92], - [6, 93], - [6, 94], - [6, 95], - [6, 96], - [6, 97], - [6, 98], - [6, 99], - [6, 100], - [6, 101], - [6, 102], - [6, 103], - [6, 104], - [6, 105], - [6, 106], - [6, 107], - [6, 108], - [6, 109], - [6, 110], - [6, 111], - [6, 112], - [6, 113], - [6, 114], - [6, 115], - [6, 116], - [6, 117], - [6, 118], - [6, 119], - [6, 120], - [6, 121], - [6, 122], - [6, 123], - [6, 124], - [6, 125], - [6, 126], - [6, 127], - [6, 128], - [6, 129], - [6, 130], - [6, 131], - [6, 132], - [6, 133], - [6, 134], - [6, 135], - [6, 136], - [6, 137], - [6, 138], - [6, 139], - [6, 140], - [6, 141], - [6, 142], - [6, 143], - [6, 144], - [6, 145], - [6, 146], - [6, 147], - [6, 148], - [6, 149], - [6, 150], - [6, 151], - [6, 152], - [6, 153], - [6, 154], - [6, 155], - [6, 156], - [6, 157], - [6, 158], - [6, 159], - [6, 160], - [6, 161], - [6, 162], - [6, 163], - [6, 164], - [6, 165], - [6, 166], - [6, 167], - [6, 168], - [6, 169], - [6, 170], - [6, 171], - [6, 172], - [6, 173], - [6, 174], - [6, 175], - [6, 176], - [6, 177], - [6, 178], - [6, 179], - [6, 180], - [6, 181], - [6, 182], - [6, 183], - [6, 184], - [6, 185], - [6, 186], - [6, 187], - [6, 188], - [6, 189], - [6, 190], - [6, 191], - [6, 192], - [6, 193], - [6, 194], - [6, 195], - [6, 196], - [6, 197], - [6, 198], - [6, 199], - [6, 200], - [6, 201], - [6, 202], - [6, 203], - [6, 204], - [6, 205], - [6, 206], - [6, 207], - [6, 208], - [6, 209], - [6, 210], - [6, 211], - [6, 212], - [6, 213], - [6, 214], - [6, 215], - [6, 216], - [6, 217], - [6, 218], - [6, 219], - [6, 220], - [6, 221], - [6, 222], - [6, 223], - [6, 224], - [6, 225], - [6, 226], - [6, 227], - [6, 228], - [6, 229], - [6, 230], - [6, 231], - [6, 232], - [6, 233], - [6, 234], - [6, 235], - [6, 236], - [6, 237], - [6, 238], - [6, 239], - [6, 240], - [6, 241], - [6, 242], - [6, 243], - [6, 244], - [6, 245], - [6, 246], - [6, 247], - [6, 248], - [6, 249], - [6, 250], - [6, 251], - [6, 252], - [6, 253], - [6, 254], - [6, 255], - [6, 256], - [6, 257], - [6, 258], - [6, 259], - [6, 260], - [6, 261], - [6, 262], - [6, 263], - [6, 264], - [6, 265], - [6, 266], - [6, 267], - [6, 268], - [6, 269], - [6, 270], - [6, 271], - [6, 272], - [6, 273], - [6, 274], - [6, 275], - [6, 276], - [6, 277], - [6, 278], - [6, 279], - [6, 280], - [6, 281], - [6, 282], - [6, 283], - [6, 284], - [6, 285], - [6, 286], - [6, 287], - [6, 288], - [6, 289], - [6, 290], - [6, 291], - [6, 292], - [6, 293], - [6, 294], - [6, 295], - [6, 296], - [6, 297], - [6, 298], - [6, 299], - [6, 300], - [6, 301], - [6, 302], - [6, 303], - [6, 304], - [6, 305], - [6, 306], - [6, 307], - [6, 308], - [6, 309], - [6, 310], - [6, 311], - [6, 312], - [6, 313], - [6, 314], - [6, 315], - [6, 316], - [6, 317], - [6, 318], - [6, 319], - [6, 320], - [6, 321], - [6, 322], - [6, 323], - [6, 324], - [6, 325], - [6, 326], - [6, 327], - [6, 328], - [6, 329], - [6, 330], - [6, 331], - [6, 332], - [6, 333], - [6, 334], - [6, 335], - [6, 336], - [6, 337], - [6, 338], - [6, 339], - [6, 340], - [6, 341], - [6, 342], - [6, 343], - [6, 344], - [6, 345], - [6, 346], - [6, 347], - [6, 348], - [6, 349], - [6, 350], - [6, 351], - [6, 352], - [6, 353], - [6, 354], - [6, 355], - [6, 356], - [6, 357], - [6, 358], - [6, 359], - [6, 360], - [6, 361], - [6, 362], - [6, 363], - [6, 364], - [6, 365], - [6, 366], - [6, 367], - [6, 368], - [6, 369], - [6, 370], - [6, 371], - [6, 372], - [6, 373], - [6, 374], - [6, 375], - [6, 376], - [6, 377], - [6, 378], - [6, 379], - [6, 380], - [6, 381], - [6, 382], - [6, 383], - [6, 384], - [6, 385], - [6, 386], - [6, 387], - [6, 388], - [6, 389], - [6, 390], - [6, 391], - [6, 392], - [6, 393], - [6, 394], - [6, 395], - [6, 396], - [6, 397], - [6, 398], - [6, 399], - [6, 400], - [6, 401], - [6, 402], - [6, 403], - [6, 404], - [6, 405], - [6, 406], - [6, 407], - [6, 408], - [6, 409], - [6, 410], - [6, 411], - [6, 412], - [6, 413], - [6, 414], - [6, 415], - [6, 416], - [6, 417], - [6, 418], - [6, 419], - [6, 420], - [6, 421], - [6, 422], - [6, 423], - [6, 424], - [6, 425], - [6, 426], - [6, 427], - [6, 428], - [6, 429], - [6, 430], - [6, 431], - [6, 432], - [6, 433], - [6, 434], - [6, 435], - [6, 436], - [6, 437], - [6, 438], - [6, 439], - [6, 440], - [6, 441], - [6, 442], - [6, 443], - [6, 444], - [6, 445], - [6, 446], - [6, 447], - [6, 448], - [6, 449], - [6, 450], - [6, 451], - [6, 452], - [6, 453], - [6, 454], - [6, 455], - [6, 456], - [6, 457], - [6, 458], - [6, 459], - [6, 460], - [6, 461], - [6, 462], - [6, 463], - [6, 464], - [6, 465], - [6, 466], - [6, 467], - [6, 468], - [6, 469], - [6, 470], - [6, 471], - [6, 472], - [6, 473], - [6, 474], - [6, 475], - [6, 476], - [6, 477], - [6, 478], - [6, 479], - [6, 480], - [6, 481], - [6, 482], - [6, 483], - [6, 484], - [6, 485], - [6, 486], - [6, 487], - [6, 488], - [6, 489], - [6, 490], - [6, 491], - [6, 492], - [6, 493], - [6, 494], - [6, 495], - [6, 496], - [6, 497], - [6, 498], - [6, 499], - [6, 500], - [7, 2], - [7, 3], - [7, 4], - [7, 5], - [7, 6], - [7, 7], - [7, 8], - [7, 9], - [7, 10], - [7, 11], - [7, 12], - [7, 13], - [7, 14], - [7, 15], - [7, 16], - [7, 17], - [7, 18], - [7, 19], - [7, 20], - [7, 21], - [7, 22], - [7, 23], - [7, 24], - [7, 25], - [7, 26], - [7, 27], - [7, 28], - [7, 29], - [7, 30], - [7, 31], - [7, 32], - [7, 33], - [7, 34], - [7, 35], - [7, 36], - [7, 37], - [7, 38], - [7, 39], - [7, 40], - [7, 41], - [7, 42], - [7, 43], - [7, 44], - [7, 45], - [7, 46], - [7, 47], - [7, 48], - [7, 49], - [7, 50], - [7, 51], - [7, 52], - [7, 53], - [7, 54], - [7, 55], - [7, 56], - [7, 57], - [7, 58], - [7, 59], - [7, 60], - [7, 61], - [7, 62], - [7, 63], - [7, 64], - [7, 65], - [7, 66], - [7, 67], - [7, 68], - [7, 69], - [7, 70], - [7, 71], - [7, 72], - [7, 73], - [7, 74], - [7, 75], - [7, 76], - [7, 77], - [7, 78], - [7, 79], - [7, 80], - [7, 81], - [7, 82], - [7, 83], - [7, 84], - [7, 85], - [7, 86], - [7, 87], - [7, 88], - [7, 89], - [7, 90], - [7, 91], - [7, 92], - [7, 93], - [7, 94], - [7, 95], - [7, 96], - [7, 97], - [7, 98], - [7, 99], - [7, 100], - [7, 101], - [7, 102], - [7, 103], - [7, 104], - [7, 105], - [7, 106], - [7, 107], - [7, 108], - [7, 109], - [7, 110], - [7, 111], - [7, 112], - [7, 113], - [7, 114], - [7, 115], - [7, 116], - [7, 117], - [7, 118], - [7, 119], - [7, 120], - [7, 121], - [7, 122], - [7, 123], - [7, 124], - [7, 125], - [7, 126], - [7, 127], - [7, 128], - [7, 129], - [7, 130], - [7, 131], - [7, 132], - [7, 133], - [7, 134], - [7, 135], - [7, 136], - [7, 137], - [7, 138], - [7, 139], - [7, 140], - [7, 141], - [7, 142], - [7, 143], - [7, 144], - [7, 145], - [7, 146], - [7, 147], - [7, 148], - [7, 149], - [7, 150], - [7, 151], - [7, 152], - [7, 153], - [7, 154], - [7, 155], - [7, 156], - [7, 157], - [7, 158], - [7, 159], - [7, 160], - [7, 161], - [7, 162], - [7, 163], - [7, 164], - [7, 165], - [7, 166], - [7, 167], - [7, 168], - [7, 169], - [7, 170], - [7, 171], - [7, 172], - [7, 173], - [7, 174], - [7, 175], - [7, 176], - [7, 177], - [7, 178], - [7, 179], - [7, 180], - [7, 181], - [7, 182], - [7, 183], - [7, 184], - [7, 185], - [7, 186], - [7, 187], - [7, 188], - [7, 189], - [7, 190], - [7, 191], - [7, 192], - [7, 193], - [7, 194], - [7, 195], - [7, 196], - [7, 197], - [7, 198], - [7, 199], - [7, 200], - [7, 201], - [7, 202], - [7, 203], - [7, 204], - [7, 205], - [7, 206], - [7, 207], - [7, 208], - [7, 209], - [7, 210], - [7, 211], - [7, 212], - [7, 213], - [7, 214], - [7, 215], - [7, 216], - [7, 217], - [7, 218], - [7, 219], - [7, 220], - [7, 221], - [7, 222], - [7, 223], - [7, 224], - [7, 225], - [7, 226], - [7, 227], - [7, 228], - [7, 229], - [7, 230], - [7, 231], - [7, 232], - [7, 233], - [7, 234], - [7, 235], - [7, 236], - [7, 237], - [7, 238], - [7, 239], - [7, 240], - [7, 241], - [7, 242], - [7, 243], - [7, 244], - [7, 245], - [7, 246], - [7, 247], - [7, 248], - [7, 249], - [7, 250], - [7, 251], - [7, 252], - [7, 253], - [7, 254], - [7, 255], - [7, 256], - [7, 257], - [7, 258], - [7, 259], - [7, 260], - [7, 261], - [7, 262], - [7, 263], - [7, 264], - [7, 265], - [7, 266], - [7, 267], - [7, 268], - [7, 269], - [7, 270], - [7, 271], - [7, 272], - [7, 273], - [7, 274], - [7, 275], - [7, 276], - [7, 277], - [7, 278], - [7, 279], - [7, 280], - [7, 281], - [7, 282], - [7, 283], - [7, 284], - [7, 285], - [7, 286], - [7, 287], - [7, 288], - [7, 289], - [7, 290], - [7, 291], - [7, 292], - [7, 293], - [7, 294], - [7, 295], - [7, 296], - [7, 297], - [7, 298], - [7, 299], - [7, 300], - [7, 301], - [7, 302], - [7, 303], - [7, 304], - [7, 305], - [7, 306], - [7, 307], - [7, 308], - [7, 309], - [7, 310], - [7, 311], - [7, 312], - [7, 313], - [7, 314], - [7, 315], - [7, 316], - [7, 317], - [7, 318], - [7, 319], - [7, 320], - [7, 321], - [7, 322], - [7, 323], - [7, 324], - [7, 325], - [7, 326], - [7, 327], - [7, 328], - [7, 329], - [7, 330], - [7, 331], - [7, 332], - [7, 333], - [7, 334], - [7, 335], - [7, 336], - [7, 337], - [7, 338], - [7, 339], - [7, 340], - [7, 341], - [7, 342], - [7, 343], - [7, 344], - [7, 345], - [7, 346], - [7, 347], - [7, 348], - [7, 349], - [7, 350], - [7, 351], - [7, 352], - [7, 353], - [7, 354], - [7, 355], - [7, 356], - [7, 357], - [7, 358], - [7, 359], - [7, 360], - [7, 361], - [7, 362], - [7, 363], - [7, 364], - [7, 365], - [7, 366], - [7, 367], - [7, 368], - [7, 369], - [7, 370], - [7, 371], - [7, 372], - [7, 373], - [7, 374], - [7, 375], - [7, 376], - [7, 377], - [7, 378], - [7, 379], - [7, 380], - [7, 381], - [7, 382], - [7, 383], - [7, 384], - [7, 385], - [7, 386], - [7, 387], - [7, 388], - [7, 389], - [7, 390], - [7, 391], - [7, 392], - [7, 393], - [7, 394], - [7, 395], - [7, 396], - [7, 397], - [7, 398], - [7, 399], - [7, 400], - [7, 401], - [7, 402], - [7, 403], - [7, 404], - [7, 405], - [7, 406], - [7, 407], - [7, 408], - [7, 409], - [7, 410], - [7, 411], - [7, 412], - [7, 413], - [7, 414], - [7, 415], - [7, 416], - [7, 417], - [7, 418], - [7, 419], - [7, 420], - [7, 421], - [7, 422], - [7, 423], - [7, 424], - [7, 425], - [7, 426], - [7, 427], - [7, 428], - [7, 429], - [7, 430], - [7, 431], - [7, 432], - [7, 433], - [7, 434], - [7, 435], - [7, 436], - [7, 437], - [7, 438], - [7, 439], - [7, 440], - [7, 441], - [7, 442], - [7, 443], - [7, 444], - [7, 445], - [7, 446], - [7, 447], - [7, 448], - [7, 449], - [7, 450], - [7, 451], - [7, 452], - [7, 453], - [7, 454], - [7, 455], - [7, 456], - [7, 457], - [7, 458], - [7, 459], - [7, 460], - [7, 461], - [7, 462], - [7, 463], - [7, 464], - [7, 465], - [7, 466], - [7, 467], - [7, 468], - [7, 469], - [7, 470], - [7, 471], - [7, 472], - [7, 473], - [7, 474], - [7, 475], - [7, 476], - [7, 477], - [7, 478], - [7, 479], - [7, 480], - [7, 481], - [7, 482], - [7, 483], - [7, 484], - [7, 485], - [7, 486], - [7, 487], - [7, 488], - [7, 489], - [7, 490], - [7, 491], - [7, 492], - [7, 493], - [7, 494], - [7, 495], - [7, 496], - [7, 497], - [7, 498], - [7, 499], - [7, 500], - [21, 4] - ] - }, - { - "x": 13, - "y": 4, - "type": "COMPUTED", - "value": "09W", - "last_modified": "2023-02-17T00:03:28.164Z" - }, - { - "x": 14, - "y": 4, - "type": "COMPUTED", - "value": "South Capitol Street", - "last_modified": "2023-02-17T00:03:28.164Z" - }, - { - "x": 15, - "y": 4, - "type": "COMPUTED", - "value": "Washington", - "last_modified": "2023-02-17T00:03:28.164Z" - }, - { - "x": 16, - "y": 4, - "type": "COMPUTED", - "value": "DC", - "last_modified": "2023-02-17T00:03:28.164Z" - }, - { - "x": 17, - "y": 4, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:28.164Z" - }, - { - "x": 18, - "y": 4, - "type": "COMPUTED", - "value": "38.86872333", - "last_modified": "2023-02-17T00:03:28.164Z" - }, - { - "x": 19, - "y": 4, - "type": "COMPUTED", - "value": "-77.00747583", - "last_modified": "2023-02-17T00:03:28.164Z" - }, - { - "x": 10, - "y": 5, - "type": "TEXT", - "value": "Distance", - "last_modified": "2023-02-16T23:50:50.106Z" - }, - { - "x": 11, - "y": 5, - "type": "PYTHON", - "value": "1476.2185 mi", - "python_code": "import numpy as np\n\n\ndef haversine(lat1, lon1, lat2, lon2, to_radians=True, earth_radius=3958.756):\n \"\"\"\n Vectorized Haversine Function\n Calculate the great circle distance between two points\n on the earth (specified in decimal degrees or in radians)\n\n All (lat, lon) coordinates must have numeric dtypes and be of equal length.\n\n \"\"\"\n\n if to_radians:\n lat1, lon1, lat2, lon2 = np.radians([lat1, lon1, lat2, lon2])\n\n a = np.sin((lat2 - lat1) / 2.0)**2 + \\\n np.cos(lat1) * np.cos(lat2) * np.sin((lon2 - lon1) / 2.0)**2\n\n return earth_radius * 2 * np.arcsin(np.sqrt(a))\n\n\nlat1 = float(c(18, 3))\nlon1 = float(c(19, 3))\nlat2 = float(c(18, 4))\nlon2 = float(c(19, 4))\n\ndistance = haversine(lat1, lon1, lat2, lon2)\nstr(distance)[:9] + \" mi\"\n", - "python_output": "", - "array_cells": [], - "dependent_cells": [ - [18, 3], - [19, 3], - [18, 4], - [19, 4] - ], - "last_modified": "2023-02-17T00:03:28.224Z", - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "1476.2185 mi", - "cells_accessed": [ - [18, 3], - [19, 3], - [18, 4], - [19, 4] - ], - "formatted_code": "import numpy as np\n\n\ndef haversine(lat1, lon1, lat2, lon2, to_radians=True, earth_radius=3958.756):\n \"\"\"\n Vectorized Haversine Function\n Calculate the great circle distance between two points\n on the earth (specified in decimal degrees or in radians)\n\n All (lat, lon) coordinates must have numeric dtypes and be of equal length.\n\n \"\"\"\n\n if to_radians:\n lat1, lon1, lat2, lon2 = np.radians([lat1, lon1, lat2, lon2])\n\n a = np.sin((lat2 - lat1) / 2.0)**2 + \\\n np.cos(lat1) * np.cos(lat2) * np.sin((lon2 - lon1) / 2.0)**2\n\n return earth_radius * 2 * np.arcsin(np.sqrt(a))\n\n\nlat1 = float(c(18, 3))\nlon1 = float(c(19, 3))\nlat2 = float(c(18, 4))\nlon2 = float(c(19, 4))\n\ndistance = haversine(lat1, lon1, lat2, lon2)\nstr(distance)[:9] + \" mi\"\n", - "error_span": null - } - }, - { - "x": 10, - "y": 8, - "type": "TEXT", - "value": "Filter airports by state", - "last_modified": "2023-02-16T23:54:00.579Z" - }, - { - "x": 12, - "y": 10, - "type": "PYTHON", - "value": "index", - "python_code": "state = c(11, 10)\n\ndf = getCells((0, 2), (7, 503), first_row_header=True)\ndf = df.fillna('')\ndf[df[\"state\"] == state]\n", - "python_output": "", - "array_cells": [ - [12, 10], - [13, 10], - [14, 10], - [15, 10], - [16, 10], - [17, 10], - [18, 10], - [19, 10], - [12, 11], - [13, 11], - [14, 11], - [15, 11], - [16, 11], - [17, 11], - [18, 11], - [19, 11], - [12, 12], - [13, 12], - [14, 12], - [15, 12], - [16, 12], - [17, 12], - [18, 12], - [19, 12], - [12, 13], - [13, 13], - [14, 13], - [15, 13], - [16, 13], - [17, 13], - [18, 13], - [19, 13], - [12, 14], - [13, 14], - [14, 14], - [15, 14], - [16, 14], - [17, 14], - [18, 14], - [19, 14], - [12, 15], - [13, 15], - [14, 15], - [15, 15], - [16, 15], - [17, 15], - [18, 15], - [19, 15], - [12, 16], - [13, 16], - [14, 16], - [15, 16], - [16, 16], - [17, 16], - [18, 16], - [19, 16], - [12, 17], - [13, 17], - [14, 17], - [15, 17], - [16, 17], - [17, 17], - [18, 17], - [19, 17], - [12, 18], - [13, 18], - [14, 18], - [15, 18], - [16, 18], - [17, 18], - [18, 18], - [19, 18], - [12, 19], - [13, 19], - [14, 19], - [15, 19], - [16, 19], - [17, 19], - [18, 19], - [19, 19], - [12, 20], - [13, 20], - [14, 20], - [15, 20], - [16, 20], - [17, 20], - [18, 20], - [19, 20], - [12, 21], - [13, 21], - [14, 21], - [15, 21], - [16, 21], - [17, 21], - [18, 21], - [19, 21], - [12, 22], - [13, 22], - [14, 22], - [15, 22], - [16, 22], - [17, 22], - [18, 22], - [19, 22], - [12, 23], - [13, 23], - [14, 23], - [15, 23], - [16, 23], - [17, 23], - [18, 23], - [19, 23], - [12, 24], - [13, 24], - [14, 24], - [15, 24], - [16, 24], - [17, 24], - [18, 24], - [19, 24], - [12, 25], - [13, 25], - [14, 25], - [15, 25], - [16, 25], - [17, 25], - [18, 25], - [19, 25], - [12, 26], - [13, 26], - [14, 26], - [15, 26], - [16, 26], - [17, 26], - [18, 26], - [19, 26], - [12, 27], - [13, 27], - [14, 27], - [15, 27], - [16, 27], - [17, 27], - [18, 27], - [19, 27], - [12, 28], - [13, 28], - [14, 28], - [15, 28], - [16, 28], - [17, 28], - [18, 28], - [19, 28], - [12, 29], - [13, 29], - [14, 29], - [15, 29], - [16, 29], - [17, 29], - [18, 29], - [19, 29], - [12, 30], - [13, 30], - [14, 30], - [15, 30], - [16, 30], - [17, 30], - [18, 30], - [19, 30], - [12, 31], - [13, 31], - [14, 31], - [15, 31], - [16, 31], - [17, 31], - [18, 31], - [19, 31] - ], - "last_modified": "2023-02-17T00:03:07.616Z", - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": " index iata name ... country latitude longitude\n3 3 01G Perry-Warsaw ... USA 42.74134667 -78.05208056\n19 19 06N Randall ... USA 41.43156583 -74.39191722\n42 42 0B8 Elizabeth ... USA 41.25130806 -72.03161139\n54 54 0G0 North Buffalo Suburban ... USA 43.10318389 -78.70334583\n57 57 0G7 Finger Lakes Regional ... USA 42.88062278 -76.78162028\n94 94 10N Wallkill ... USA 41.62787111 -74.13375583\n138 138 1B1 Columbia Cty ... USA 42.29130028 -73.71031944\n156 156 1G6 Michael ... USA 43.18166667 -76.12777778\n161 161 1I5 Freehold ... USA 42.36425 -74.06596806\n178 178 1N2 Spadaro ... USA 40.82787639 -72.74871083\n203 203 20N Kingston-Ulster ... USA 41.9852525 -73.96409722\n214 214 23N Bayport Aerodrome ... USA 40.75843139 -73.05372083\n335 335 3G7 Williamson/Sodus ... USA 43.23472222 -77.12097222\n391 391 44N Sky Acres ... USA 41.70742861 -73.73802889\n397 397 46N Sky Park ... USA 41.98458333 -73.83596556\n418 418 4B0 South Albany ... USA 42.56072611 -73.83395639\n419 419 4B1 Duanesburg ... USA 42.75840889 -74.13290472\n420 420 4B6 Ticonderoga Muni ... USA 43.87700278 -73.41317639\n421 421 4B7 Schroon Lake ... USA 43.86256083 -73.74262972\n430 430 4G2 Hamburg Inc. ... USA 42.7008925 -78.91475694\n432 432 4G6 Hornell Muni ... USA 42.38214444 -77.6821125\n\n[21 rows x 8 columns]", - "cells_accessed": [ - [11, 10], - [0, 2], - [0, 3], - [0, 4], - [0, 5], - [0, 6], - [0, 7], - [0, 8], - [0, 9], - [0, 10], - [0, 11], - [0, 12], - [0, 13], - [0, 14], - [0, 15], - [0, 16], - [0, 17], - [0, 18], - [0, 19], - [0, 20], - [0, 21], - [0, 22], - [0, 23], - [0, 24], - [0, 25], - [0, 26], - [0, 27], - [0, 28], - [0, 29], - [0, 30], - [0, 31], - [0, 32], - [0, 33], - [0, 34], - [0, 35], - [0, 36], - [0, 37], - [0, 38], - [0, 39], - [0, 40], - [0, 41], - [0, 42], - [0, 43], - [0, 44], - [0, 45], - [0, 46], - [0, 47], - [0, 48], - [0, 49], - [0, 50], - [0, 51], - [0, 52], - [0, 53], - [0, 54], - [0, 55], - [0, 56], - [0, 57], - [0, 58], - [0, 59], - [0, 60], - [0, 61], - [0, 62], - [0, 63], - [0, 64], - [0, 65], - [0, 66], - [0, 67], - [0, 68], - [0, 69], - [0, 70], - [0, 71], - [0, 72], - [0, 73], - [0, 74], - [0, 75], - [0, 76], - [0, 77], - [0, 78], - [0, 79], - [0, 80], - [0, 81], - [0, 82], - [0, 83], - [0, 84], - [0, 85], - [0, 86], - [0, 87], - [0, 88], - [0, 89], - [0, 90], - [0, 91], - [0, 92], - [0, 93], - [0, 94], - [0, 95], - [0, 96], - [0, 97], - [0, 98], - [0, 99], - [0, 100], - [0, 101], - [0, 102], - [0, 103], - [0, 104], - [0, 105], - [0, 106], - [0, 107], - [0, 108], - [0, 109], - [0, 110], - [0, 111], - [0, 112], - [0, 113], - [0, 114], - [0, 115], - [0, 116], - [0, 117], - [0, 118], - [0, 119], - [0, 120], - [0, 121], - [0, 122], - [0, 123], - [0, 124], - [0, 125], - [0, 126], - [0, 127], - [0, 128], - [0, 129], - [0, 130], - [0, 131], - [0, 132], - [0, 133], - [0, 134], - [0, 135], - [0, 136], - [0, 137], - [0, 138], - [0, 139], - [0, 140], - [0, 141], - [0, 142], - [0, 143], - [0, 144], - [0, 145], - [0, 146], - [0, 147], - [0, 148], - [0, 149], - [0, 150], - [0, 151], - [0, 152], - [0, 153], - [0, 154], - [0, 155], - [0, 156], - [0, 157], - [0, 158], - [0, 159], - [0, 160], - [0, 161], - [0, 162], - [0, 163], - [0, 164], - [0, 165], - [0, 166], - [0, 167], - [0, 168], - [0, 169], - [0, 170], - [0, 171], - [0, 172], - [0, 173], - [0, 174], - [0, 175], - [0, 176], - [0, 177], - [0, 178], - [0, 179], - [0, 180], - [0, 181], - [0, 182], - [0, 183], - [0, 184], - [0, 185], - [0, 186], - [0, 187], - [0, 188], - [0, 189], - [0, 190], - [0, 191], - [0, 192], - [0, 193], - [0, 194], - [0, 195], - [0, 196], - [0, 197], - [0, 198], - [0, 199], - [0, 200], - [0, 201], - [0, 202], - [0, 203], - [0, 204], - [0, 205], - [0, 206], - [0, 207], - [0, 208], - [0, 209], - [0, 210], - [0, 211], - [0, 212], - [0, 213], - [0, 214], - [0, 215], - [0, 216], - [0, 217], - [0, 218], - [0, 219], - [0, 220], - [0, 221], - [0, 222], - [0, 223], - [0, 224], - [0, 225], - [0, 226], - [0, 227], - [0, 228], - [0, 229], - [0, 230], - [0, 231], - [0, 232], - [0, 233], - [0, 234], - [0, 235], - [0, 236], - [0, 237], - [0, 238], - [0, 239], - [0, 240], - [0, 241], - [0, 242], - [0, 243], - [0, 244], - [0, 245], - [0, 246], - [0, 247], - [0, 248], - [0, 249], - [0, 250], - [0, 251], - [0, 252], - [0, 253], - [0, 254], - [0, 255], - [0, 256], - [0, 257], - [0, 258], - [0, 259], - [0, 260], - [0, 261], - [0, 262], - [0, 263], - [0, 264], - [0, 265], - [0, 266], - [0, 267], - [0, 268], - [0, 269], - [0, 270], - [0, 271], - [0, 272], - [0, 273], - [0, 274], - [0, 275], - [0, 276], - [0, 277], - [0, 278], - [0, 279], - [0, 280], - [0, 281], - [0, 282], - [0, 283], - [0, 284], - [0, 285], - [0, 286], - [0, 287], - [0, 288], - [0, 289], - [0, 290], - [0, 291], - [0, 292], - [0, 293], - [0, 294], - [0, 295], - [0, 296], - [0, 297], - [0, 298], - [0, 299], - [0, 300], - [0, 301], - [0, 302], - [0, 303], - [0, 304], - [0, 305], - [0, 306], - [0, 307], - [0, 308], - [0, 309], - [0, 310], - [0, 311], - [0, 312], - [0, 313], - [0, 314], - [0, 315], - [0, 316], - [0, 317], - [0, 318], - [0, 319], - [0, 320], - [0, 321], - [0, 322], - [0, 323], - [0, 324], - [0, 325], - [0, 326], - [0, 327], - [0, 328], - [0, 329], - [0, 330], - [0, 331], - [0, 332], - [0, 333], - [0, 334], - [0, 335], - [0, 336], - [0, 337], - [0, 338], - [0, 339], - [0, 340], - [0, 341], - [0, 342], - [0, 343], - [0, 344], - [0, 345], - [0, 346], - [0, 347], - [0, 348], - [0, 349], - [0, 350], - [0, 351], - [0, 352], - [0, 353], - [0, 354], - [0, 355], - [0, 356], - [0, 357], - [0, 358], - [0, 359], - [0, 360], - [0, 361], - [0, 362], - [0, 363], - [0, 364], - [0, 365], - [0, 366], - [0, 367], - [0, 368], - [0, 369], - [0, 370], - [0, 371], - [0, 372], - [0, 373], - [0, 374], - [0, 375], - [0, 376], - [0, 377], - [0, 378], - [0, 379], - [0, 380], - [0, 381], - [0, 382], - [0, 383], - [0, 384], - [0, 385], - [0, 386], - [0, 387], - [0, 388], - [0, 389], - [0, 390], - [0, 391], - [0, 392], - [0, 393], - [0, 394], - [0, 395], - [0, 396], - [0, 397], - [0, 398], - [0, 399], - [0, 400], - [0, 401], - [0, 402], - [0, 403], - [0, 404], - [0, 405], - [0, 406], - [0, 407], - [0, 408], - [0, 409], - [0, 410], - [0, 411], - [0, 412], - [0, 413], - [0, 414], - [0, 415], - [0, 416], - [0, 417], - [0, 418], - [0, 419], - [0, 420], - [0, 421], - [0, 422], - [0, 423], - [0, 424], - [0, 425], - [0, 426], - [0, 427], - [0, 428], - [0, 429], - [0, 430], - [0, 431], - [0, 432], - [0, 433], - [0, 434], - [0, 435], - [0, 436], - [0, 437], - [0, 438], - [0, 439], - [0, 440], - [0, 441], - [0, 442], - [0, 443], - [0, 444], - [0, 445], - [0, 446], - [0, 447], - [0, 448], - [0, 449], - [0, 450], - [0, 451], - [0, 452], - [0, 453], - [0, 454], - [0, 455], - [0, 456], - [0, 457], - [0, 458], - [0, 459], - [0, 460], - [0, 461], - [0, 462], - [0, 463], - [0, 464], - [0, 465], - [0, 466], - [0, 467], - [0, 468], - [0, 469], - [0, 470], - [0, 471], - [0, 472], - [0, 473], - [0, 474], - [0, 475], - [0, 476], - [0, 477], - [0, 478], - [0, 479], - [0, 480], - [0, 481], - [0, 482], - [0, 483], - [0, 484], - [0, 485], - [0, 486], - [0, 487], - [0, 488], - [0, 489], - [0, 490], - [0, 491], - [0, 492], - [0, 493], - [0, 494], - [0, 495], - [0, 496], - [0, 497], - [0, 498], - [0, 499], - [0, 500], - [0, 501], - [0, 502], - [0, 503], - [1, 2], - [1, 3], - [1, 4], - [1, 5], - [1, 6], - [1, 7], - [1, 8], - [1, 9], - [1, 10], - [1, 11], - [1, 12], - [1, 13], - [1, 14], - [1, 15], - [1, 16], - [1, 17], - [1, 18], - [1, 19], - [1, 20], - [1, 21], - [1, 22], - [1, 23], - [1, 24], - [1, 25], - [1, 26], - [1, 27], - [1, 28], - [1, 29], - [1, 30], - [1, 31], - [1, 32], - [1, 33], - [1, 34], - [1, 35], - [1, 36], - [1, 37], - [1, 38], - [1, 39], - [1, 40], - [1, 41], - [1, 42], - [1, 43], - [1, 44], - [1, 45], - [1, 46], - [1, 47], - [1, 48], - [1, 49], - [1, 50], - [1, 51], - [1, 52], - [1, 53], - [1, 54], - [1, 55], - [1, 56], - [1, 57], - [1, 58], - [1, 59], - [1, 60], - [1, 61], - [1, 62], - [1, 63], - [1, 64], - [1, 65], - [1, 66], - [1, 67], - [1, 68], - [1, 69], - [1, 70], - [1, 71], - [1, 72], - [1, 73], - [1, 74], - [1, 75], - [1, 76], - [1, 77], - [1, 78], - [1, 79], - [1, 80], - [1, 81], - [1, 82], - [1, 83], - [1, 84], - [1, 85], - [1, 86], - [1, 87], - [1, 88], - [1, 89], - [1, 90], - [1, 91], - [1, 92], - [1, 93], - [1, 94], - [1, 95], - [1, 96], - [1, 97], - [1, 98], - [1, 99], - [1, 100], - [1, 101], - [1, 102], - [1, 103], - [1, 104], - [1, 105], - [1, 106], - [1, 107], - [1, 108], - [1, 109], - [1, 110], - [1, 111], - [1, 112], - [1, 113], - [1, 114], - [1, 115], - [1, 116], - [1, 117], - [1, 118], - [1, 119], - [1, 120], - [1, 121], - [1, 122], - [1, 123], - [1, 124], - [1, 125], - [1, 126], - [1, 127], - [1, 128], - [1, 129], - [1, 130], - [1, 131], - [1, 132], - [1, 133], - [1, 134], - [1, 135], - [1, 136], - [1, 137], - [1, 138], - [1, 139], - [1, 140], - [1, 141], - [1, 142], - [1, 143], - [1, 144], - [1, 145], - [1, 146], - [1, 147], - [1, 148], - [1, 149], - [1, 150], - [1, 151], - [1, 152], - [1, 153], - [1, 154], - [1, 155], - [1, 156], - [1, 157], - [1, 158], - [1, 159], - [1, 160], - [1, 161], - [1, 162], - [1, 163], - [1, 164], - [1, 165], - [1, 166], - [1, 167], - [1, 168], - [1, 169], - [1, 170], - [1, 171], - [1, 172], - [1, 173], - [1, 174], - [1, 175], - [1, 176], - [1, 177], - [1, 178], - [1, 179], - [1, 180], - [1, 181], - [1, 182], - [1, 183], - [1, 184], - [1, 185], - [1, 186], - [1, 187], - [1, 188], - [1, 189], - [1, 190], - [1, 191], - [1, 192], - [1, 193], - [1, 194], - [1, 195], - [1, 196], - [1, 197], - [1, 198], - [1, 199], - [1, 200], - [1, 201], - [1, 202], - [1, 203], - [1, 204], - [1, 205], - [1, 206], - [1, 207], - [1, 208], - [1, 209], - [1, 210], - [1, 211], - [1, 212], - [1, 213], - [1, 214], - [1, 215], - [1, 216], - [1, 217], - [1, 218], - [1, 219], - [1, 220], - [1, 221], - [1, 222], - [1, 223], - [1, 224], - [1, 225], - [1, 226], - [1, 227], - [1, 228], - [1, 229], - [1, 230], - [1, 231], - [1, 232], - [1, 233], - [1, 234], - [1, 235], - [1, 236], - [1, 237], - [1, 238], - [1, 239], - [1, 240], - [1, 241], - [1, 242], - [1, 243], - [1, 244], - [1, 245], - [1, 246], - [1, 247], - [1, 248], - [1, 249], - [1, 250], - [1, 251], - [1, 252], - [1, 253], - [1, 254], - [1, 255], - [1, 256], - [1, 257], - [1, 258], - [1, 259], - [1, 260], - [1, 261], - [1, 262], - [1, 263], - [1, 264], - [1, 265], - [1, 266], - [1, 267], - [1, 268], - [1, 269], - [1, 270], - [1, 271], - [1, 272], - [1, 273], - [1, 274], - [1, 275], - [1, 276], - [1, 277], - [1, 278], - [1, 279], - [1, 280], - [1, 281], - [1, 282], - [1, 283], - [1, 284], - [1, 285], - [1, 286], - [1, 287], - [1, 288], - [1, 289], - [1, 290], - [1, 291], - [1, 292], - [1, 293], - [1, 294], - [1, 295], - [1, 296], - [1, 297], - [1, 298], - [1, 299], - [1, 300], - [1, 301], - [1, 302], - [1, 303], - [1, 304], - [1, 305], - [1, 306], - [1, 307], - [1, 308], - [1, 309], - [1, 310], - [1, 311], - [1, 312], - [1, 313], - [1, 314], - [1, 315], - [1, 316], - [1, 317], - [1, 318], - [1, 319], - [1, 320], - [1, 321], - [1, 322], - [1, 323], - [1, 324], - [1, 325], - [1, 326], - [1, 327], - [1, 328], - [1, 329], - [1, 330], - [1, 331], - [1, 332], - [1, 333], - [1, 334], - [1, 335], - [1, 336], - [1, 337], - [1, 338], - [1, 339], - [1, 340], - [1, 341], - [1, 342], - [1, 343], - [1, 344], - [1, 345], - [1, 346], - [1, 347], - [1, 348], - [1, 349], - [1, 350], - [1, 351], - [1, 352], - [1, 353], - [1, 354], - [1, 355], - [1, 356], - [1, 357], - [1, 358], - [1, 359], - [1, 360], - [1, 361], - [1, 362], - [1, 363], - [1, 364], - [1, 365], - [1, 366], - [1, 367], - [1, 368], - [1, 369], - [1, 370], - [1, 371], - [1, 372], - [1, 373], - [1, 374], - [1, 375], - [1, 376], - [1, 377], - [1, 378], - [1, 379], - [1, 380], - [1, 381], - [1, 382], - [1, 383], - [1, 384], - [1, 385], - [1, 386], - [1, 387], - [1, 388], - [1, 389], - [1, 390], - [1, 391], - [1, 392], - [1, 393], - [1, 394], - [1, 395], - [1, 396], - [1, 397], - [1, 398], - [1, 399], - [1, 400], - [1, 401], - [1, 402], - [1, 403], - [1, 404], - [1, 405], - [1, 406], - [1, 407], - [1, 408], - [1, 409], - [1, 410], - [1, 411], - [1, 412], - [1, 413], - [1, 414], - [1, 415], - [1, 416], - [1, 417], - [1, 418], - [1, 419], - [1, 420], - [1, 421], - [1, 422], - [1, 423], - [1, 424], - [1, 425], - [1, 426], - [1, 427], - [1, 428], - [1, 429], - [1, 430], - [1, 431], - [1, 432], - [1, 433], - [1, 434], - [1, 435], - [1, 436], - [1, 437], - [1, 438], - [1, 439], - [1, 440], - [1, 441], - [1, 442], - [1, 443], - [1, 444], - [1, 445], - [1, 446], - [1, 447], - [1, 448], - [1, 449], - [1, 450], - [1, 451], - [1, 452], - [1, 453], - [1, 454], - [1, 455], - [1, 456], - [1, 457], - [1, 458], - [1, 459], - [1, 460], - [1, 461], - [1, 462], - [1, 463], - [1, 464], - [1, 465], - [1, 466], - [1, 467], - [1, 468], - [1, 469], - [1, 470], - [1, 471], - [1, 472], - [1, 473], - [1, 474], - [1, 475], - [1, 476], - [1, 477], - [1, 478], - [1, 479], - [1, 480], - [1, 481], - [1, 482], - [1, 483], - [1, 484], - [1, 485], - [1, 486], - [1, 487], - [1, 488], - [1, 489], - [1, 490], - [1, 491], - [1, 492], - [1, 493], - [1, 494], - [1, 495], - [1, 496], - [1, 497], - [1, 498], - [1, 499], - [1, 500], - [1, 501], - [1, 502], - [1, 503], - [2, 2], - [2, 3], - [2, 4], - [2, 5], - [2, 6], - [2, 7], - [2, 8], - [2, 9], - [2, 10], - [2, 11], - [2, 12], - [2, 13], - [2, 14], - [2, 15], - [2, 16], - [2, 17], - [2, 18], - [2, 19], - [2, 20], - [2, 21], - [2, 22], - [2, 23], - [2, 24], - [2, 25], - [2, 26], - [2, 27], - [2, 28], - [2, 29], - [2, 30], - [2, 31], - [2, 32], - [2, 33], - [2, 34], - [2, 35], - [2, 36], - [2, 37], - [2, 38], - [2, 39], - [2, 40], - [2, 41], - [2, 42], - [2, 43], - [2, 44], - [2, 45], - [2, 46], - [2, 47], - [2, 48], - [2, 49], - [2, 50], - [2, 51], - [2, 52], - [2, 53], - [2, 54], - [2, 55], - [2, 56], - [2, 57], - [2, 58], - [2, 59], - [2, 60], - [2, 61], - [2, 62], - [2, 63], - [2, 64], - [2, 65], - [2, 66], - [2, 67], - [2, 68], - [2, 69], - [2, 70], - [2, 71], - [2, 72], - [2, 73], - [2, 74], - [2, 75], - [2, 76], - [2, 77], - [2, 78], - [2, 79], - [2, 80], - [2, 81], - [2, 82], - [2, 83], - [2, 84], - [2, 85], - [2, 86], - [2, 87], - [2, 88], - [2, 89], - [2, 90], - [2, 91], - [2, 92], - [2, 93], - [2, 94], - [2, 95], - [2, 96], - [2, 97], - [2, 98], - [2, 99], - [2, 100], - [2, 101], - [2, 102], - [2, 103], - [2, 104], - [2, 105], - [2, 106], - [2, 107], - [2, 108], - [2, 109], - [2, 110], - [2, 111], - [2, 112], - [2, 113], - [2, 114], - [2, 115], - [2, 116], - [2, 117], - [2, 118], - [2, 119], - [2, 120], - [2, 121], - [2, 122], - [2, 123], - [2, 124], - [2, 125], - [2, 126], - [2, 127], - [2, 128], - [2, 129], - [2, 130], - [2, 131], - [2, 132], - [2, 133], - [2, 134], - [2, 135], - [2, 136], - [2, 137], - [2, 138], - [2, 139], - [2, 140], - [2, 141], - [2, 142], - [2, 143], - [2, 144], - [2, 145], - [2, 146], - [2, 147], - [2, 148], - [2, 149], - [2, 150], - [2, 151], - [2, 152], - [2, 153], - [2, 154], - [2, 155], - [2, 156], - [2, 157], - [2, 158], - [2, 159], - [2, 160], - [2, 161], - [2, 162], - [2, 163], - [2, 164], - [2, 165], - [2, 166], - [2, 167], - [2, 168], - [2, 169], - [2, 170], - [2, 171], - [2, 172], - [2, 173], - [2, 174], - [2, 175], - [2, 176], - [2, 177], - [2, 178], - [2, 179], - [2, 180], - [2, 181], - [2, 182], - [2, 183], - [2, 184], - [2, 185], - [2, 186], - [2, 187], - [2, 188], - [2, 189], - [2, 190], - [2, 191], - [2, 192], - [2, 193], - [2, 194], - [2, 195], - [2, 196], - [2, 197], - [2, 198], - [2, 199], - [2, 200], - [2, 201], - [2, 202], - [2, 203], - [2, 204], - [2, 205], - [2, 206], - [2, 207], - [2, 208], - [2, 209], - [2, 210], - [2, 211], - [2, 212], - [2, 213], - [2, 214], - [2, 215], - [2, 216], - [2, 217], - [2, 218], - [2, 219], - [2, 220], - [2, 221], - [2, 222], - [2, 223], - [2, 224], - [2, 225], - [2, 226], - [2, 227], - [2, 228], - [2, 229], - [2, 230], - [2, 231], - [2, 232], - [2, 233], - [2, 234], - [2, 235], - [2, 236], - [2, 237], - [2, 238], - [2, 239], - [2, 240], - [2, 241], - [2, 242], - [2, 243], - [2, 244], - [2, 245], - [2, 246], - [2, 247], - [2, 248], - [2, 249], - [2, 250], - [2, 251], - [2, 252], - [2, 253], - [2, 254], - [2, 255], - [2, 256], - [2, 257], - [2, 258], - [2, 259], - [2, 260], - [2, 261], - [2, 262], - [2, 263], - [2, 264], - [2, 265], - [2, 266], - [2, 267], - [2, 268], - [2, 269], - [2, 270], - [2, 271], - [2, 272], - [2, 273], - [2, 274], - [2, 275], - [2, 276], - [2, 277], - [2, 278], - [2, 279], - [2, 280], - [2, 281], - [2, 282], - [2, 283], - [2, 284], - [2, 285], - [2, 286], - [2, 287], - [2, 288], - [2, 289], - [2, 290], - [2, 291], - [2, 292], - [2, 293], - [2, 294], - [2, 295], - [2, 296], - [2, 297], - [2, 298], - [2, 299], - [2, 300], - [2, 301], - [2, 302], - [2, 303], - [2, 304], - [2, 305], - [2, 306], - [2, 307], - [2, 308], - [2, 309], - [2, 310], - [2, 311], - [2, 312], - [2, 313], - [2, 314], - [2, 315], - [2, 316], - [2, 317], - [2, 318], - [2, 319], - [2, 320], - [2, 321], - [2, 322], - [2, 323], - [2, 324], - [2, 325], - [2, 326], - [2, 327], - [2, 328], - [2, 329], - [2, 330], - [2, 331], - [2, 332], - [2, 333], - [2, 334], - [2, 335], - [2, 336], - [2, 337], - [2, 338], - [2, 339], - [2, 340], - [2, 341], - [2, 342], - [2, 343], - [2, 344], - [2, 345], - [2, 346], - [2, 347], - [2, 348], - [2, 349], - [2, 350], - [2, 351], - [2, 352], - [2, 353], - [2, 354], - [2, 355], - [2, 356], - [2, 357], - [2, 358], - [2, 359], - [2, 360], - [2, 361], - [2, 362], - [2, 363], - [2, 364], - [2, 365], - [2, 366], - [2, 367], - [2, 368], - [2, 369], - [2, 370], - [2, 371], - [2, 372], - [2, 373], - [2, 374], - [2, 375], - [2, 376], - [2, 377], - [2, 378], - [2, 379], - [2, 380], - [2, 381], - [2, 382], - [2, 383], - [2, 384], - [2, 385], - [2, 386], - [2, 387], - [2, 388], - [2, 389], - [2, 390], - [2, 391], - [2, 392], - [2, 393], - [2, 394], - [2, 395], - [2, 396], - [2, 397], - [2, 398], - [2, 399], - [2, 400], - [2, 401], - [2, 402], - [2, 403], - [2, 404], - [2, 405], - [2, 406], - [2, 407], - [2, 408], - [2, 409], - [2, 410], - [2, 411], - [2, 412], - [2, 413], - [2, 414], - [2, 415], - [2, 416], - [2, 417], - [2, 418], - [2, 419], - [2, 420], - [2, 421], - [2, 422], - [2, 423], - [2, 424], - [2, 425], - [2, 426], - [2, 427], - [2, 428], - [2, 429], - [2, 430], - [2, 431], - [2, 432], - [2, 433], - [2, 434], - [2, 435], - [2, 436], - [2, 437], - [2, 438], - [2, 439], - [2, 440], - [2, 441], - [2, 442], - [2, 443], - [2, 444], - [2, 445], - [2, 446], - [2, 447], - [2, 448], - [2, 449], - [2, 450], - [2, 451], - [2, 452], - [2, 453], - [2, 454], - [2, 455], - [2, 456], - [2, 457], - [2, 458], - [2, 459], - [2, 460], - [2, 461], - [2, 462], - [2, 463], - [2, 464], - [2, 465], - [2, 466], - [2, 467], - [2, 468], - [2, 469], - [2, 470], - [2, 471], - [2, 472], - [2, 473], - [2, 474], - [2, 475], - [2, 476], - [2, 477], - [2, 478], - [2, 479], - [2, 480], - [2, 481], - [2, 482], - [2, 483], - [2, 484], - [2, 485], - [2, 486], - [2, 487], - [2, 488], - [2, 489], - [2, 490], - [2, 491], - [2, 492], - [2, 493], - [2, 494], - [2, 495], - [2, 496], - [2, 497], - [2, 498], - [2, 499], - [2, 500], - [2, 501], - [2, 502], - [2, 503], - [3, 2], - [3, 3], - [3, 4], - [3, 5], - [3, 6], - [3, 7], - [3, 8], - [3, 9], - [3, 10], - [3, 11], - [3, 12], - [3, 13], - [3, 14], - [3, 15], - [3, 16], - [3, 17], - [3, 18], - [3, 19], - [3, 20], - [3, 21], - [3, 22], - [3, 23], - [3, 24], - [3, 25], - [3, 26], - [3, 27], - [3, 28], - [3, 29], - [3, 30], - [3, 31], - [3, 32], - [3, 33], - [3, 34], - [3, 35], - [3, 36], - [3, 37], - [3, 38], - [3, 39], - [3, 40], - [3, 41], - [3, 42], - [3, 43], - [3, 44], - [3, 45], - [3, 46], - [3, 47], - [3, 48], - [3, 49], - [3, 50], - [3, 51], - [3, 52], - [3, 53], - [3, 54], - [3, 55], - [3, 56], - [3, 57], - [3, 58], - [3, 59], - [3, 60], - [3, 61], - [3, 62], - [3, 63], - [3, 64], - [3, 65], - [3, 66], - [3, 67], - [3, 68], - [3, 69], - [3, 70], - [3, 71], - [3, 72], - [3, 73], - [3, 74], - [3, 75], - [3, 76], - [3, 77], - [3, 78], - [3, 79], - [3, 80], - [3, 81], - [3, 82], - [3, 83], - [3, 84], - [3, 85], - [3, 86], - [3, 87], - [3, 88], - [3, 89], - [3, 90], - [3, 91], - [3, 92], - [3, 93], - [3, 94], - [3, 95], - [3, 96], - [3, 97], - [3, 98], - [3, 99], - [3, 100], - [3, 101], - [3, 102], - [3, 103], - [3, 104], - [3, 105], - [3, 106], - [3, 107], - [3, 108], - [3, 109], - [3, 110], - [3, 111], - [3, 112], - [3, 113], - [3, 114], - [3, 115], - [3, 116], - [3, 117], - [3, 118], - [3, 119], - [3, 120], - [3, 121], - [3, 122], - [3, 123], - [3, 124], - [3, 125], - [3, 126], - [3, 127], - [3, 128], - [3, 129], - [3, 130], - [3, 131], - [3, 132], - [3, 133], - [3, 134], - [3, 135], - [3, 136], - [3, 137], - [3, 138], - [3, 139], - [3, 140], - [3, 141], - [3, 142], - [3, 143], - [3, 144], - [3, 145], - [3, 146], - [3, 147], - [3, 148], - [3, 149], - [3, 150], - [3, 151], - [3, 152], - [3, 153], - [3, 154], - [3, 155], - [3, 156], - [3, 157], - [3, 158], - [3, 159], - [3, 160], - [3, 161], - [3, 162], - [3, 163], - [3, 164], - [3, 165], - [3, 166], - [3, 167], - [3, 168], - [3, 169], - [3, 170], - [3, 171], - [3, 172], - [3, 173], - [3, 174], - [3, 175], - [3, 176], - [3, 177], - [3, 178], - [3, 179], - [3, 180], - [3, 181], - [3, 182], - [3, 183], - [3, 184], - [3, 185], - [3, 186], - [3, 187], - [3, 188], - [3, 189], - [3, 190], - [3, 191], - [3, 192], - [3, 193], - [3, 194], - [3, 195], - [3, 196], - [3, 197], - [3, 198], - [3, 199], - [3, 200], - [3, 201], - [3, 202], - [3, 203], - [3, 204], - [3, 205], - [3, 206], - [3, 207], - [3, 208], - [3, 209], - [3, 210], - [3, 211], - [3, 212], - [3, 213], - [3, 214], - [3, 215], - [3, 216], - [3, 217], - [3, 218], - [3, 219], - [3, 220], - [3, 221], - [3, 222], - [3, 223], - [3, 224], - [3, 225], - [3, 226], - [3, 227], - [3, 228], - [3, 229], - [3, 230], - [3, 231], - [3, 232], - [3, 233], - [3, 234], - [3, 235], - [3, 236], - [3, 237], - [3, 238], - [3, 239], - [3, 240], - [3, 241], - [3, 242], - [3, 243], - [3, 244], - [3, 245], - [3, 246], - [3, 247], - [3, 248], - [3, 249], - [3, 250], - [3, 251], - [3, 252], - [3, 253], - [3, 254], - [3, 255], - [3, 256], - [3, 257], - [3, 258], - [3, 259], - [3, 260], - [3, 261], - [3, 262], - [3, 263], - [3, 264], - [3, 265], - [3, 266], - [3, 267], - [3, 268], - [3, 269], - [3, 270], - [3, 271], - [3, 272], - [3, 273], - [3, 274], - [3, 275], - [3, 276], - [3, 277], - [3, 278], - [3, 279], - [3, 280], - [3, 281], - [3, 282], - [3, 283], - [3, 284], - [3, 285], - [3, 286], - [3, 287], - [3, 288], - [3, 289], - [3, 290], - [3, 291], - [3, 292], - [3, 293], - [3, 294], - [3, 295], - [3, 296], - [3, 297], - [3, 298], - [3, 299], - [3, 300], - [3, 301], - [3, 302], - [3, 303], - [3, 304], - [3, 305], - [3, 306], - [3, 307], - [3, 308], - [3, 309], - [3, 310], - [3, 311], - [3, 312], - [3, 313], - [3, 314], - [3, 315], - [3, 316], - [3, 317], - [3, 318], - [3, 319], - [3, 320], - [3, 321], - [3, 322], - [3, 323], - [3, 324], - [3, 325], - [3, 326], - [3, 327], - [3, 328], - [3, 329], - [3, 330], - [3, 331], - [3, 332], - [3, 333], - [3, 334], - [3, 335], - [3, 336], - [3, 337], - [3, 338], - [3, 339], - [3, 340], - [3, 341], - [3, 342], - [3, 343], - [3, 344], - [3, 345], - [3, 346], - [3, 347], - [3, 348], - [3, 349], - [3, 350], - [3, 351], - [3, 352], - [3, 353], - [3, 354], - [3, 355], - [3, 356], - [3, 357], - [3, 358], - [3, 359], - [3, 360], - [3, 361], - [3, 362], - [3, 363], - [3, 364], - [3, 365], - [3, 366], - [3, 367], - [3, 368], - [3, 369], - [3, 370], - [3, 371], - [3, 372], - [3, 373], - [3, 374], - [3, 375], - [3, 376], - [3, 377], - [3, 378], - [3, 379], - [3, 380], - [3, 381], - [3, 382], - [3, 383], - [3, 384], - [3, 385], - [3, 386], - [3, 387], - [3, 388], - [3, 389], - [3, 390], - [3, 391], - [3, 392], - [3, 393], - [3, 394], - [3, 395], - [3, 396], - [3, 397], - [3, 398], - [3, 399], - [3, 400], - [3, 401], - [3, 402], - [3, 403], - [3, 404], - [3, 405], - [3, 406], - [3, 407], - [3, 408], - [3, 409], - [3, 410], - [3, 411], - [3, 412], - [3, 413], - [3, 414], - [3, 415], - [3, 416], - [3, 417], - [3, 418], - [3, 419], - [3, 420], - [3, 421], - [3, 422], - [3, 423], - [3, 424], - [3, 425], - [3, 426], - [3, 427], - [3, 428], - [3, 429], - [3, 430], - [3, 431], - [3, 432], - [3, 433], - [3, 434], - [3, 435], - [3, 436], - [3, 437], - [3, 438], - [3, 439], - [3, 440], - [3, 441], - [3, 442], - [3, 443], - [3, 444], - [3, 445], - [3, 446], - [3, 447], - [3, 448], - [3, 449], - [3, 450], - [3, 451], - [3, 452], - [3, 453], - [3, 454], - [3, 455], - [3, 456], - [3, 457], - [3, 458], - [3, 459], - [3, 460], - [3, 461], - [3, 462], - [3, 463], - [3, 464], - [3, 465], - [3, 466], - [3, 467], - [3, 468], - [3, 469], - [3, 470], - [3, 471], - [3, 472], - [3, 473], - [3, 474], - [3, 475], - [3, 476], - [3, 477], - [3, 478], - [3, 479], - [3, 480], - [3, 481], - [3, 482], - [3, 483], - [3, 484], - [3, 485], - [3, 486], - [3, 487], - [3, 488], - [3, 489], - [3, 490], - [3, 491], - [3, 492], - [3, 493], - [3, 494], - [3, 495], - [3, 496], - [3, 497], - [3, 498], - [3, 499], - [3, 500], - [3, 501], - [3, 502], - [3, 503], - [4, 2], - [4, 3], - [4, 4], - [4, 5], - [4, 6], - [4, 7], - [4, 8], - [4, 9], - [4, 10], - [4, 11], - [4, 12], - [4, 13], - [4, 14], - [4, 15], - [4, 16], - [4, 17], - [4, 18], - [4, 19], - [4, 20], - [4, 21], - [4, 22], - [4, 23], - [4, 24], - [4, 25], - [4, 26], - [4, 27], - [4, 28], - [4, 29], - [4, 30], - [4, 31], - [4, 32], - [4, 33], - [4, 34], - [4, 35], - [4, 36], - [4, 37], - [4, 38], - [4, 39], - [4, 40], - [4, 41], - [4, 42], - [4, 43], - [4, 44], - [4, 45], - [4, 46], - [4, 47], - [4, 48], - [4, 49], - [4, 50], - [4, 51], - [4, 52], - [4, 53], - [4, 54], - [4, 55], - [4, 56], - [4, 57], - [4, 58], - [4, 59], - [4, 60], - [4, 61], - [4, 62], - [4, 63], - [4, 64], - [4, 65], - [4, 66], - [4, 67], - [4, 68], - [4, 69], - [4, 70], - [4, 71], - [4, 72], - [4, 73], - [4, 74], - [4, 75], - [4, 76], - [4, 77], - [4, 78], - [4, 79], - [4, 80], - [4, 81], - [4, 82], - [4, 83], - [4, 84], - [4, 85], - [4, 86], - [4, 87], - [4, 88], - [4, 89], - [4, 90], - [4, 91], - [4, 92], - [4, 93], - [4, 94], - [4, 95], - [4, 96], - [4, 97], - [4, 98], - [4, 99], - [4, 100], - [4, 101], - [4, 102], - [4, 103], - [4, 104], - [4, 105], - [4, 106], - [4, 107], - [4, 108], - [4, 109], - [4, 110], - [4, 111], - [4, 112], - [4, 113], - [4, 114], - [4, 115], - [4, 116], - [4, 117], - [4, 118], - [4, 119], - [4, 120], - [4, 121], - [4, 122], - [4, 123], - [4, 124], - [4, 125], - [4, 126], - [4, 127], - [4, 128], - [4, 129], - [4, 130], - [4, 131], - [4, 132], - [4, 133], - [4, 134], - [4, 135], - [4, 136], - [4, 137], - [4, 138], - [4, 139], - [4, 140], - [4, 141], - [4, 142], - [4, 143], - [4, 144], - [4, 145], - [4, 146], - [4, 147], - [4, 148], - [4, 149], - [4, 150], - [4, 151], - [4, 152], - [4, 153], - [4, 154], - [4, 155], - [4, 156], - [4, 157], - [4, 158], - [4, 159], - [4, 160], - [4, 161], - [4, 162], - [4, 163], - [4, 164], - [4, 165], - [4, 166], - [4, 167], - [4, 168], - [4, 169], - [4, 170], - [4, 171], - [4, 172], - [4, 173], - [4, 174], - [4, 175], - [4, 176], - [4, 177], - [4, 178], - [4, 179], - [4, 180], - [4, 181], - [4, 182], - [4, 183], - [4, 184], - [4, 185], - [4, 186], - [4, 187], - [4, 188], - [4, 189], - [4, 190], - [4, 191], - [4, 192], - [4, 193], - [4, 194], - [4, 195], - [4, 196], - [4, 197], - [4, 198], - [4, 199], - [4, 200], - [4, 201], - [4, 202], - [4, 203], - [4, 204], - [4, 205], - [4, 206], - [4, 207], - [4, 208], - [4, 209], - [4, 210], - [4, 211], - [4, 212], - [4, 213], - [4, 214], - [4, 215], - [4, 216], - [4, 217], - [4, 218], - [4, 219], - [4, 220], - [4, 221], - [4, 222], - [4, 223], - [4, 224], - [4, 225], - [4, 226], - [4, 227], - [4, 228], - [4, 229], - [4, 230], - [4, 231], - [4, 232], - [4, 233], - [4, 234], - [4, 235], - [4, 236], - [4, 237], - [4, 238], - [4, 239], - [4, 240], - [4, 241], - [4, 242], - [4, 243], - [4, 244], - [4, 245], - [4, 246], - [4, 247], - [4, 248], - [4, 249], - [4, 250], - [4, 251], - [4, 252], - [4, 253], - [4, 254], - [4, 255], - [4, 256], - [4, 257], - [4, 258], - [4, 259], - [4, 260], - [4, 261], - [4, 262], - [4, 263], - [4, 264], - [4, 265], - [4, 266], - [4, 267], - [4, 268], - [4, 269], - [4, 270], - [4, 271], - [4, 272], - [4, 273], - [4, 274], - [4, 275], - [4, 276], - [4, 277], - [4, 278], - [4, 279], - [4, 280], - [4, 281], - [4, 282], - [4, 283], - [4, 284], - [4, 285], - [4, 286], - [4, 287], - [4, 288], - [4, 289], - [4, 290], - [4, 291], - [4, 292], - [4, 293], - [4, 294], - [4, 295], - [4, 296], - [4, 297], - [4, 298], - [4, 299], - [4, 300], - [4, 301], - [4, 302], - [4, 303], - [4, 304], - [4, 305], - [4, 306], - [4, 307], - [4, 308], - [4, 309], - [4, 310], - [4, 311], - [4, 312], - [4, 313], - [4, 314], - [4, 315], - [4, 316], - [4, 317], - [4, 318], - [4, 319], - [4, 320], - [4, 321], - [4, 322], - [4, 323], - [4, 324], - [4, 325], - [4, 326], - [4, 327], - [4, 328], - [4, 329], - [4, 330], - [4, 331], - [4, 332], - [4, 333], - [4, 334], - [4, 335], - [4, 336], - [4, 337], - [4, 338], - [4, 339], - [4, 340], - [4, 341], - [4, 342], - [4, 343], - [4, 344], - [4, 345], - [4, 346], - [4, 347], - [4, 348], - [4, 349], - [4, 350], - [4, 351], - [4, 352], - [4, 353], - [4, 354], - [4, 355], - [4, 356], - [4, 357], - [4, 358], - [4, 359], - [4, 360], - [4, 361], - [4, 362], - [4, 363], - [4, 364], - [4, 365], - [4, 366], - [4, 367], - [4, 368], - [4, 369], - [4, 370], - [4, 371], - [4, 372], - [4, 373], - [4, 374], - [4, 375], - [4, 376], - [4, 377], - [4, 378], - [4, 379], - [4, 380], - [4, 381], - [4, 382], - [4, 383], - [4, 384], - [4, 385], - [4, 386], - [4, 387], - [4, 388], - [4, 389], - [4, 390], - [4, 391], - [4, 392], - [4, 393], - [4, 394], - [4, 395], - [4, 396], - [4, 397], - [4, 398], - [4, 399], - [4, 400], - [4, 401], - [4, 402], - [4, 403], - [4, 404], - [4, 405], - [4, 406], - [4, 407], - [4, 408], - [4, 409], - [4, 410], - [4, 411], - [4, 412], - [4, 413], - [4, 414], - [4, 415], - [4, 416], - [4, 417], - [4, 418], - [4, 419], - [4, 420], - [4, 421], - [4, 422], - [4, 423], - [4, 424], - [4, 425], - [4, 426], - [4, 427], - [4, 428], - [4, 429], - [4, 430], - [4, 431], - [4, 432], - [4, 433], - [4, 434], - [4, 435], - [4, 436], - [4, 437], - [4, 438], - [4, 439], - [4, 440], - [4, 441], - [4, 442], - [4, 443], - [4, 444], - [4, 445], - [4, 446], - [4, 447], - [4, 448], - [4, 449], - [4, 450], - [4, 451], - [4, 452], - [4, 453], - [4, 454], - [4, 455], - [4, 456], - [4, 457], - [4, 458], - [4, 459], - [4, 460], - [4, 461], - [4, 462], - [4, 463], - [4, 464], - [4, 465], - [4, 466], - [4, 467], - [4, 468], - [4, 469], - [4, 470], - [4, 471], - [4, 472], - [4, 473], - [4, 474], - [4, 475], - [4, 476], - [4, 477], - [4, 478], - [4, 479], - [4, 480], - [4, 481], - [4, 482], - [4, 483], - [4, 484], - [4, 485], - [4, 486], - [4, 487], - [4, 488], - [4, 489], - [4, 490], - [4, 491], - [4, 492], - [4, 493], - [4, 494], - [4, 495], - [4, 496], - [4, 497], - [4, 498], - [4, 499], - [4, 500], - [4, 501], - [4, 502], - [4, 503], - [5, 2], - [5, 3], - [5, 4], - [5, 5], - [5, 6], - [5, 7], - [5, 8], - [5, 9], - [5, 10], - [5, 11], - [5, 12], - [5, 13], - [5, 14], - [5, 15], - [5, 16], - [5, 17], - [5, 18], - [5, 19], - [5, 20], - [5, 21], - [5, 22], - [5, 23], - [5, 24], - [5, 25], - [5, 26], - [5, 27], - [5, 28], - [5, 29], - [5, 30], - [5, 31], - [5, 32], - [5, 33], - [5, 34], - [5, 35], - [5, 36], - [5, 37], - [5, 38], - [5, 39], - [5, 40], - [5, 41], - [5, 42], - [5, 43], - [5, 44], - [5, 45], - [5, 46], - [5, 47], - [5, 48], - [5, 49], - [5, 50], - [5, 51], - [5, 52], - [5, 53], - [5, 54], - [5, 55], - [5, 56], - [5, 57], - [5, 58], - [5, 59], - [5, 60], - [5, 61], - [5, 62], - [5, 63], - [5, 64], - [5, 65], - [5, 66], - [5, 67], - [5, 68], - [5, 69], - [5, 70], - [5, 71], - [5, 72], - [5, 73], - [5, 74], - [5, 75], - [5, 76], - [5, 77], - [5, 78], - [5, 79], - [5, 80], - [5, 81], - [5, 82], - [5, 83], - [5, 84], - [5, 85], - [5, 86], - [5, 87], - [5, 88], - [5, 89], - [5, 90], - [5, 91], - [5, 92], - [5, 93], - [5, 94], - [5, 95], - [5, 96], - [5, 97], - [5, 98], - [5, 99], - [5, 100], - [5, 101], - [5, 102], - [5, 103], - [5, 104], - [5, 105], - [5, 106], - [5, 107], - [5, 108], - [5, 109], - [5, 110], - [5, 111], - [5, 112], - [5, 113], - [5, 114], - [5, 115], - [5, 116], - [5, 117], - [5, 118], - [5, 119], - [5, 120], - [5, 121], - [5, 122], - [5, 123], - [5, 124], - [5, 125], - [5, 126], - [5, 127], - [5, 128], - [5, 129], - [5, 130], - [5, 131], - [5, 132], - [5, 133], - [5, 134], - [5, 135], - [5, 136], - [5, 137], - [5, 138], - [5, 139], - [5, 140], - [5, 141], - [5, 142], - [5, 143], - [5, 144], - [5, 145], - [5, 146], - [5, 147], - [5, 148], - [5, 149], - [5, 150], - [5, 151], - [5, 152], - [5, 153], - [5, 154], - [5, 155], - [5, 156], - [5, 157], - [5, 158], - [5, 159], - [5, 160], - [5, 161], - [5, 162], - [5, 163], - [5, 164], - [5, 165], - [5, 166], - [5, 167], - [5, 168], - [5, 169], - [5, 170], - [5, 171], - [5, 172], - [5, 173], - [5, 174], - [5, 175], - [5, 176], - [5, 177], - [5, 178], - [5, 179], - [5, 180], - [5, 181], - [5, 182], - [5, 183], - [5, 184], - [5, 185], - [5, 186], - [5, 187], - [5, 188], - [5, 189], - [5, 190], - [5, 191], - [5, 192], - [5, 193], - [5, 194], - [5, 195], - [5, 196], - [5, 197], - [5, 198], - [5, 199], - [5, 200], - [5, 201], - [5, 202], - [5, 203], - [5, 204], - [5, 205], - [5, 206], - [5, 207], - [5, 208], - [5, 209], - [5, 210], - [5, 211], - [5, 212], - [5, 213], - [5, 214], - [5, 215], - [5, 216], - [5, 217], - [5, 218], - [5, 219], - [5, 220], - [5, 221], - [5, 222], - [5, 223], - [5, 224], - [5, 225], - [5, 226], - [5, 227], - [5, 228], - [5, 229], - [5, 230], - [5, 231], - [5, 232], - [5, 233], - [5, 234], - [5, 235], - [5, 236], - [5, 237], - [5, 238], - [5, 239], - [5, 240], - [5, 241], - [5, 242], - [5, 243], - [5, 244], - [5, 245], - [5, 246], - [5, 247], - [5, 248], - [5, 249], - [5, 250], - [5, 251], - [5, 252], - [5, 253], - [5, 254], - [5, 255], - [5, 256], - [5, 257], - [5, 258], - [5, 259], - [5, 260], - [5, 261], - [5, 262], - [5, 263], - [5, 264], - [5, 265], - [5, 266], - [5, 267], - [5, 268], - [5, 269], - [5, 270], - [5, 271], - [5, 272], - [5, 273], - [5, 274], - [5, 275], - [5, 276], - [5, 277], - [5, 278], - [5, 279], - [5, 280], - [5, 281], - [5, 282], - [5, 283], - [5, 284], - [5, 285], - [5, 286], - [5, 287], - [5, 288], - [5, 289], - [5, 290], - [5, 291], - [5, 292], - [5, 293], - [5, 294], - [5, 295], - [5, 296], - [5, 297], - [5, 298], - [5, 299], - [5, 300], - [5, 301], - [5, 302], - [5, 303], - [5, 304], - [5, 305], - [5, 306], - [5, 307], - [5, 308], - [5, 309], - [5, 310], - [5, 311], - [5, 312], - [5, 313], - [5, 314], - [5, 315], - [5, 316], - [5, 317], - [5, 318], - [5, 319], - [5, 320], - [5, 321], - [5, 322], - [5, 323], - [5, 324], - [5, 325], - [5, 326], - [5, 327], - [5, 328], - [5, 329], - [5, 330], - [5, 331], - [5, 332], - [5, 333], - [5, 334], - [5, 335], - [5, 336], - [5, 337], - [5, 338], - [5, 339], - [5, 340], - [5, 341], - [5, 342], - [5, 343], - [5, 344], - [5, 345], - [5, 346], - [5, 347], - [5, 348], - [5, 349], - [5, 350], - [5, 351], - [5, 352], - [5, 353], - [5, 354], - [5, 355], - [5, 356], - [5, 357], - [5, 358], - [5, 359], - [5, 360], - [5, 361], - [5, 362], - [5, 363], - [5, 364], - [5, 365], - [5, 366], - [5, 367], - [5, 368], - [5, 369], - [5, 370], - [5, 371], - [5, 372], - [5, 373], - [5, 374], - [5, 375], - [5, 376], - [5, 377], - [5, 378], - [5, 379], - [5, 380], - [5, 381], - [5, 382], - [5, 383], - [5, 384], - [5, 385], - [5, 386], - [5, 387], - [5, 388], - [5, 389], - [5, 390], - [5, 391], - [5, 392], - [5, 393], - [5, 394], - [5, 395], - [5, 396], - [5, 397], - [5, 398], - [5, 399], - [5, 400], - [5, 401], - [5, 402], - [5, 403], - [5, 404], - [5, 405], - [5, 406], - [5, 407], - [5, 408], - [5, 409], - [5, 410], - [5, 411], - [5, 412], - [5, 413], - [5, 414], - [5, 415], - [5, 416], - [5, 417], - [5, 418], - [5, 419], - [5, 420], - [5, 421], - [5, 422], - [5, 423], - [5, 424], - [5, 425], - [5, 426], - [5, 427], - [5, 428], - [5, 429], - [5, 430], - [5, 431], - [5, 432], - [5, 433], - [5, 434], - [5, 435], - [5, 436], - [5, 437], - [5, 438], - [5, 439], - [5, 440], - [5, 441], - [5, 442], - [5, 443], - [5, 444], - [5, 445], - [5, 446], - [5, 447], - [5, 448], - [5, 449], - [5, 450], - [5, 451], - [5, 452], - [5, 453], - [5, 454], - [5, 455], - [5, 456], - [5, 457], - [5, 458], - [5, 459], - [5, 460], - [5, 461], - [5, 462], - [5, 463], - [5, 464], - [5, 465], - [5, 466], - [5, 467], - [5, 468], - [5, 469], - [5, 470], - [5, 471], - [5, 472], - [5, 473], - [5, 474], - [5, 475], - [5, 476], - [5, 477], - [5, 478], - [5, 479], - [5, 480], - [5, 481], - [5, 482], - [5, 483], - [5, 484], - [5, 485], - [5, 486], - [5, 487], - [5, 488], - [5, 489], - [5, 490], - [5, 491], - [5, 492], - [5, 493], - [5, 494], - [5, 495], - [5, 496], - [5, 497], - [5, 498], - [5, 499], - [5, 500], - [5, 501], - [5, 502], - [5, 503], - [6, 2], - [6, 3], - [6, 4], - [6, 5], - [6, 6], - [6, 7], - [6, 8], - [6, 9], - [6, 10], - [6, 11], - [6, 12], - [6, 13], - [6, 14], - [6, 15], - [6, 16], - [6, 17], - [6, 18], - [6, 19], - [6, 20], - [6, 21], - [6, 22], - [6, 23], - [6, 24], - [6, 25], - [6, 26], - [6, 27], - [6, 28], - [6, 29], - [6, 30], - [6, 31], - [6, 32], - [6, 33], - [6, 34], - [6, 35], - [6, 36], - [6, 37], - [6, 38], - [6, 39], - [6, 40], - [6, 41], - [6, 42], - [6, 43], - [6, 44], - [6, 45], - [6, 46], - [6, 47], - [6, 48], - [6, 49], - [6, 50], - [6, 51], - [6, 52], - [6, 53], - [6, 54], - [6, 55], - [6, 56], - [6, 57], - [6, 58], - [6, 59], - [6, 60], - [6, 61], - [6, 62], - [6, 63], - [6, 64], - [6, 65], - [6, 66], - [6, 67], - [6, 68], - [6, 69], - [6, 70], - [6, 71], - [6, 72], - [6, 73], - [6, 74], - [6, 75], - [6, 76], - [6, 77], - [6, 78], - [6, 79], - [6, 80], - [6, 81], - [6, 82], - [6, 83], - [6, 84], - [6, 85], - [6, 86], - [6, 87], - [6, 88], - [6, 89], - [6, 90], - [6, 91], - [6, 92], - [6, 93], - [6, 94], - [6, 95], - [6, 96], - [6, 97], - [6, 98], - [6, 99], - [6, 100], - [6, 101], - [6, 102], - [6, 103], - [6, 104], - [6, 105], - [6, 106], - [6, 107], - [6, 108], - [6, 109], - [6, 110], - [6, 111], - [6, 112], - [6, 113], - [6, 114], - [6, 115], - [6, 116], - [6, 117], - [6, 118], - [6, 119], - [6, 120], - [6, 121], - [6, 122], - [6, 123], - [6, 124], - [6, 125], - [6, 126], - [6, 127], - [6, 128], - [6, 129], - [6, 130], - [6, 131], - [6, 132], - [6, 133], - [6, 134], - [6, 135], - [6, 136], - [6, 137], - [6, 138], - [6, 139], - [6, 140], - [6, 141], - [6, 142], - [6, 143], - [6, 144], - [6, 145], - [6, 146], - [6, 147], - [6, 148], - [6, 149], - [6, 150], - [6, 151], - [6, 152], - [6, 153], - [6, 154], - [6, 155], - [6, 156], - [6, 157], - [6, 158], - [6, 159], - [6, 160], - [6, 161], - [6, 162], - [6, 163], - [6, 164], - [6, 165], - [6, 166], - [6, 167], - [6, 168], - [6, 169], - [6, 170], - [6, 171], - [6, 172], - [6, 173], - [6, 174], - [6, 175], - [6, 176], - [6, 177], - [6, 178], - [6, 179], - [6, 180], - [6, 181], - [6, 182], - [6, 183], - [6, 184], - [6, 185], - [6, 186], - [6, 187], - [6, 188], - [6, 189], - [6, 190], - [6, 191], - [6, 192], - [6, 193], - [6, 194], - [6, 195], - [6, 196], - [6, 197], - [6, 198], - [6, 199], - [6, 200], - [6, 201], - [6, 202], - [6, 203], - [6, 204], - [6, 205], - [6, 206], - [6, 207], - [6, 208], - [6, 209], - [6, 210], - [6, 211], - [6, 212], - [6, 213], - [6, 214], - [6, 215], - [6, 216], - [6, 217], - [6, 218], - [6, 219], - [6, 220], - [6, 221], - [6, 222], - [6, 223], - [6, 224], - [6, 225], - [6, 226], - [6, 227], - [6, 228], - [6, 229], - [6, 230], - [6, 231], - [6, 232], - [6, 233], - [6, 234], - [6, 235], - [6, 236], - [6, 237], - [6, 238], - [6, 239], - [6, 240], - [6, 241], - [6, 242], - [6, 243], - [6, 244], - [6, 245], - [6, 246], - [6, 247], - [6, 248], - [6, 249], - [6, 250], - [6, 251], - [6, 252], - [6, 253], - [6, 254], - [6, 255], - [6, 256], - [6, 257], - [6, 258], - [6, 259], - [6, 260], - [6, 261], - [6, 262], - [6, 263], - [6, 264], - [6, 265], - [6, 266], - [6, 267], - [6, 268], - [6, 269], - [6, 270], - [6, 271], - [6, 272], - [6, 273], - [6, 274], - [6, 275], - [6, 276], - [6, 277], - [6, 278], - [6, 279], - [6, 280], - [6, 281], - [6, 282], - [6, 283], - [6, 284], - [6, 285], - [6, 286], - [6, 287], - [6, 288], - [6, 289], - [6, 290], - [6, 291], - [6, 292], - [6, 293], - [6, 294], - [6, 295], - [6, 296], - [6, 297], - [6, 298], - [6, 299], - [6, 300], - [6, 301], - [6, 302], - [6, 303], - [6, 304], - [6, 305], - [6, 306], - [6, 307], - [6, 308], - [6, 309], - [6, 310], - [6, 311], - [6, 312], - [6, 313], - [6, 314], - [6, 315], - [6, 316], - [6, 317], - [6, 318], - [6, 319], - [6, 320], - [6, 321], - [6, 322], - [6, 323], - [6, 324], - [6, 325], - [6, 326], - [6, 327], - [6, 328], - [6, 329], - [6, 330], - [6, 331], - [6, 332], - [6, 333], - [6, 334], - [6, 335], - [6, 336], - [6, 337], - [6, 338], - [6, 339], - [6, 340], - [6, 341], - [6, 342], - [6, 343], - [6, 344], - [6, 345], - [6, 346], - [6, 347], - [6, 348], - [6, 349], - [6, 350], - [6, 351], - [6, 352], - [6, 353], - [6, 354], - [6, 355], - [6, 356], - [6, 357], - [6, 358], - [6, 359], - [6, 360], - [6, 361], - [6, 362], - [6, 363], - [6, 364], - [6, 365], - [6, 366], - [6, 367], - [6, 368], - [6, 369], - [6, 370], - [6, 371], - [6, 372], - [6, 373], - [6, 374], - [6, 375], - [6, 376], - [6, 377], - [6, 378], - [6, 379], - [6, 380], - [6, 381], - [6, 382], - [6, 383], - [6, 384], - [6, 385], - [6, 386], - [6, 387], - [6, 388], - [6, 389], - [6, 390], - [6, 391], - [6, 392], - [6, 393], - [6, 394], - [6, 395], - [6, 396], - [6, 397], - [6, 398], - [6, 399], - [6, 400], - [6, 401], - [6, 402], - [6, 403], - [6, 404], - [6, 405], - [6, 406], - [6, 407], - [6, 408], - [6, 409], - [6, 410], - [6, 411], - [6, 412], - [6, 413], - [6, 414], - [6, 415], - [6, 416], - [6, 417], - [6, 418], - [6, 419], - [6, 420], - [6, 421], - [6, 422], - [6, 423], - [6, 424], - [6, 425], - [6, 426], - [6, 427], - [6, 428], - [6, 429], - [6, 430], - [6, 431], - [6, 432], - [6, 433], - [6, 434], - [6, 435], - [6, 436], - [6, 437], - [6, 438], - [6, 439], - [6, 440], - [6, 441], - [6, 442], - [6, 443], - [6, 444], - [6, 445], - [6, 446], - [6, 447], - [6, 448], - [6, 449], - [6, 450], - [6, 451], - [6, 452], - [6, 453], - [6, 454], - [6, 455], - [6, 456], - [6, 457], - [6, 458], - [6, 459], - [6, 460], - [6, 461], - [6, 462], - [6, 463], - [6, 464], - [6, 465], - [6, 466], - [6, 467], - [6, 468], - [6, 469], - [6, 470], - [6, 471], - [6, 472], - [6, 473], - [6, 474], - [6, 475], - [6, 476], - [6, 477], - [6, 478], - [6, 479], - [6, 480], - [6, 481], - [6, 482], - [6, 483], - [6, 484], - [6, 485], - [6, 486], - [6, 487], - [6, 488], - [6, 489], - [6, 490], - [6, 491], - [6, 492], - [6, 493], - [6, 494], - [6, 495], - [6, 496], - [6, 497], - [6, 498], - [6, 499], - [6, 500], - [6, 501], - [6, 502], - [6, 503], - [7, 2], - [7, 3], - [7, 4], - [7, 5], - [7, 6], - [7, 7], - [7, 8], - [7, 9], - [7, 10], - [7, 11], - [7, 12], - [7, 13], - [7, 14], - [7, 15], - [7, 16], - [7, 17], - [7, 18], - [7, 19], - [7, 20], - [7, 21], - [7, 22], - [7, 23], - [7, 24], - [7, 25], - [7, 26], - [7, 27], - [7, 28], - [7, 29], - [7, 30], - [7, 31], - [7, 32], - [7, 33], - [7, 34], - [7, 35], - [7, 36], - [7, 37], - [7, 38], - [7, 39], - [7, 40], - [7, 41], - [7, 42], - [7, 43], - [7, 44], - [7, 45], - [7, 46], - [7, 47], - [7, 48], - [7, 49], - [7, 50], - [7, 51], - [7, 52], - [7, 53], - [7, 54], - [7, 55], - [7, 56], - [7, 57], - [7, 58], - [7, 59], - [7, 60], - [7, 61], - [7, 62], - [7, 63], - [7, 64], - [7, 65], - [7, 66], - [7, 67], - [7, 68], - [7, 69], - [7, 70], - [7, 71], - [7, 72], - [7, 73], - [7, 74], - [7, 75], - [7, 76], - [7, 77], - [7, 78], - [7, 79], - [7, 80], - [7, 81], - [7, 82], - [7, 83], - [7, 84], - [7, 85], - [7, 86], - [7, 87], - [7, 88], - [7, 89], - [7, 90], - [7, 91], - [7, 92], - [7, 93], - [7, 94], - [7, 95], - [7, 96], - [7, 97], - [7, 98], - [7, 99], - [7, 100], - [7, 101], - [7, 102], - [7, 103], - [7, 104], - [7, 105], - [7, 106], - [7, 107], - [7, 108], - [7, 109], - [7, 110], - [7, 111], - [7, 112], - [7, 113], - [7, 114], - [7, 115], - [7, 116], - [7, 117], - [7, 118], - [7, 119], - [7, 120], - [7, 121], - [7, 122], - [7, 123], - [7, 124], - [7, 125], - [7, 126], - [7, 127], - [7, 128], - [7, 129], - [7, 130], - [7, 131], - [7, 132], - [7, 133], - [7, 134], - [7, 135], - [7, 136], - [7, 137], - [7, 138], - [7, 139], - [7, 140], - [7, 141], - [7, 142], - [7, 143], - [7, 144], - [7, 145], - [7, 146], - [7, 147], - [7, 148], - [7, 149], - [7, 150], - [7, 151], - [7, 152], - [7, 153], - [7, 154], - [7, 155], - [7, 156], - [7, 157], - [7, 158], - [7, 159], - [7, 160], - [7, 161], - [7, 162], - [7, 163], - [7, 164], - [7, 165], - [7, 166], - [7, 167], - [7, 168], - [7, 169], - [7, 170], - [7, 171], - [7, 172], - [7, 173], - [7, 174], - [7, 175], - [7, 176], - [7, 177], - [7, 178], - [7, 179], - [7, 180], - [7, 181], - [7, 182], - [7, 183], - [7, 184], - [7, 185], - [7, 186], - [7, 187], - [7, 188], - [7, 189], - [7, 190], - [7, 191], - [7, 192], - [7, 193], - [7, 194], - [7, 195], - [7, 196], - [7, 197], - [7, 198], - [7, 199], - [7, 200], - [7, 201], - [7, 202], - [7, 203], - [7, 204], - [7, 205], - [7, 206], - [7, 207], - [7, 208], - [7, 209], - [7, 210], - [7, 211], - [7, 212], - [7, 213], - [7, 214], - [7, 215], - [7, 216], - [7, 217], - [7, 218], - [7, 219], - [7, 220], - [7, 221], - [7, 222], - [7, 223], - [7, 224], - [7, 225], - [7, 226], - [7, 227], - [7, 228], - [7, 229], - [7, 230], - [7, 231], - [7, 232], - [7, 233], - [7, 234], - [7, 235], - [7, 236], - [7, 237], - [7, 238], - [7, 239], - [7, 240], - [7, 241], - [7, 242], - [7, 243], - [7, 244], - [7, 245], - [7, 246], - [7, 247], - [7, 248], - [7, 249], - [7, 250], - [7, 251], - [7, 252], - [7, 253], - [7, 254], - [7, 255], - [7, 256], - [7, 257], - [7, 258], - [7, 259], - [7, 260], - [7, 261], - [7, 262], - [7, 263], - [7, 264], - [7, 265], - [7, 266], - [7, 267], - [7, 268], - [7, 269], - [7, 270], - [7, 271], - [7, 272], - [7, 273], - [7, 274], - [7, 275], - [7, 276], - [7, 277], - [7, 278], - [7, 279], - [7, 280], - [7, 281], - [7, 282], - [7, 283], - [7, 284], - [7, 285], - [7, 286], - [7, 287], - [7, 288], - [7, 289], - [7, 290], - [7, 291], - [7, 292], - [7, 293], - [7, 294], - [7, 295], - [7, 296], - [7, 297], - [7, 298], - [7, 299], - [7, 300], - [7, 301], - [7, 302], - [7, 303], - [7, 304], - [7, 305], - [7, 306], - [7, 307], - [7, 308], - [7, 309], - [7, 310], - [7, 311], - [7, 312], - [7, 313], - [7, 314], - [7, 315], - [7, 316], - [7, 317], - [7, 318], - [7, 319], - [7, 320], - [7, 321], - [7, 322], - [7, 323], - [7, 324], - [7, 325], - [7, 326], - [7, 327], - [7, 328], - [7, 329], - [7, 330], - [7, 331], - [7, 332], - [7, 333], - [7, 334], - [7, 335], - [7, 336], - [7, 337], - [7, 338], - [7, 339], - [7, 340], - [7, 341], - [7, 342], - [7, 343], - [7, 344], - [7, 345], - [7, 346], - [7, 347], - [7, 348], - [7, 349], - [7, 350], - [7, 351], - [7, 352], - [7, 353], - [7, 354], - [7, 355], - [7, 356], - [7, 357], - [7, 358], - [7, 359], - [7, 360], - [7, 361], - [7, 362], - [7, 363], - [7, 364], - [7, 365], - [7, 366], - [7, 367], - [7, 368], - [7, 369], - [7, 370], - [7, 371], - [7, 372], - [7, 373], - [7, 374], - [7, 375], - [7, 376], - [7, 377], - [7, 378], - [7, 379], - [7, 380], - [7, 381], - [7, 382], - [7, 383], - [7, 384], - [7, 385], - [7, 386], - [7, 387], - [7, 388], - [7, 389], - [7, 390], - [7, 391], - [7, 392], - [7, 393], - [7, 394], - [7, 395], - [7, 396], - [7, 397], - [7, 398], - [7, 399], - [7, 400], - [7, 401], - [7, 402], - [7, 403], - [7, 404], - [7, 405], - [7, 406], - [7, 407], - [7, 408], - [7, 409], - [7, 410], - [7, 411], - [7, 412], - [7, 413], - [7, 414], - [7, 415], - [7, 416], - [7, 417], - [7, 418], - [7, 419], - [7, 420], - [7, 421], - [7, 422], - [7, 423], - [7, 424], - [7, 425], - [7, 426], - [7, 427], - [7, 428], - [7, 429], - [7, 430], - [7, 431], - [7, 432], - [7, 433], - [7, 434], - [7, 435], - [7, 436], - [7, 437], - [7, 438], - [7, 439], - [7, 440], - [7, 441], - [7, 442], - [7, 443], - [7, 444], - [7, 445], - [7, 446], - [7, 447], - [7, 448], - [7, 449], - [7, 450], - [7, 451], - [7, 452], - [7, 453], - [7, 454], - [7, 455], - [7, 456], - [7, 457], - [7, 458], - [7, 459], - [7, 460], - [7, 461], - [7, 462], - [7, 463], - [7, 464], - [7, 465], - [7, 466], - [7, 467], - [7, 468], - [7, 469], - [7, 470], - [7, 471], - [7, 472], - [7, 473], - [7, 474], - [7, 475], - [7, 476], - [7, 477], - [7, 478], - [7, 479], - [7, 480], - [7, 481], - [7, 482], - [7, 483], - [7, 484], - [7, 485], - [7, 486], - [7, 487], - [7, 488], - [7, 489], - [7, 490], - [7, 491], - [7, 492], - [7, 493], - [7, 494], - [7, 495], - [7, 496], - [7, 497], - [7, 498], - [7, 499], - [7, 500], - [7, 501], - [7, 502], - [7, 503] - ], - "array_output": [ - ["index", "iata", "name", "city", "state", "country", "latitude", "longitude"], - ["3", "01G", "Perry-Warsaw", "Perry", "NY", "USA", "42.74134667", "-78.05208056"], - ["19", "06N", "Randall", "Middletown", "NY", "USA", "41.43156583", "-74.39191722"], - ["42", "0B8", "Elizabeth", "Fishers Island", "NY", "USA", "41.25130806", "-72.03161139"], - ["54", "0G0", "North Buffalo Suburban", "Lockport", "NY", "USA", "43.10318389", "-78.70334583"], - ["57", "0G7", "Finger Lakes Regional", "Seneca Falls", "NY", "USA", "42.88062278", "-76.78162028"], - ["94", "10N", "Wallkill", "Wallkill", "NY", "USA", "41.62787111", "-74.13375583"], - ["138", "1B1", "Columbia Cty", "Hudson", "NY", "USA", "42.29130028", "-73.71031944"], - ["156", "1G6", "Michael", "Cicero", "NY", "USA", "43.18166667", "-76.12777778"], - ["161", "1I5", "Freehold", "Freehold", "NY", "USA", "42.36425", "-74.06596806"], - ["178", "1N2", "Spadaro", "East Moriches", "NY", "USA", "40.82787639", "-72.74871083"], - ["203", "20N", "Kingston-Ulster", "Kingston", "NY", "USA", "41.9852525", "-73.96409722"], - ["214", "23N", "Bayport Aerodrome", "Bayport", "NY", "USA", "40.75843139", "-73.05372083"], - ["335", "3G7", "Williamson/Sodus", "Williamson", "NY", "USA", "43.23472222", "-77.12097222"], - ["391", "44N", "Sky Acres", "Millbrook", "NY", "USA", "41.70742861", "-73.73802889"], - ["397", "46N", "Sky Park", "Red Hook", "NY", "USA", "41.98458333", "-73.83596556"], - ["418", "4B0", "South Albany", "South Bethlehem", "NY", "USA", "42.56072611", "-73.83395639"], - ["419", "4B1", "Duanesburg", "Duanesburg", "NY", "USA", "42.75840889", "-74.13290472"], - ["420", "4B6", "Ticonderoga Muni", "Ticonderoga", "NY", "USA", "43.87700278", "-73.41317639"], - ["421", "4B7", "Schroon Lake", "Schroon Lake", "NY", "USA", "43.86256083", "-73.74262972"], - ["430", "4G2", "Hamburg Inc.", "Hamburg", "NY", "USA", "42.7008925", "-78.91475694"], - ["432", "4G6", "Hornell Muni", "Hornell", "NY", "USA", "42.38214444", "-77.6821125"] - ], - "formatted_code": "state = c(11, 10)\n\ndf = getCells((0, 2), (7, 503), first_row_header=True)\ndf = df.fillna('')\ndf[df[\"state\"] == state]\n", - "error_span": null - }, - "dependent_cells": [ - [11, 0], - [0, 2], - [0, 3], - [0, 4], - [0, 5], - [0, 6], - [0, 7], - [0, 8], - [0, 9], - [0, 10], - [0, 11], - [0, 12], - [0, 13], - [0, 14], - [0, 15], - [0, 16], - [0, 17], - [0, 18], - [0, 19], - [0, 20], - [0, 21], - [0, 22], - [0, 23], - [0, 24], - [0, 25], - [0, 26], - [0, 27], - [0, 28], - [0, 29], - [0, 30], - [0, 31], - [0, 32], - [0, 33], - [0, 34], - [0, 35], - [0, 36], - [0, 37], - [0, 38], - [0, 39], - [0, 40], - [0, 41], - [0, 42], - [0, 43], - [0, 44], - [0, 45], - [0, 46], - [0, 47], - [0, 48], - [0, 49], - [0, 50], - [0, 51], - [0, 52], - [0, 53], - [0, 54], - [0, 55], - [0, 56], - [0, 57], - [0, 58], - [0, 59], - [0, 60], - [0, 61], - [0, 62], - [0, 63], - [0, 64], - [0, 65], - [0, 66], - [0, 67], - [0, 68], - [0, 69], - [0, 70], - [0, 71], - [0, 72], - [0, 73], - [0, 74], - [0, 75], - [0, 76], - [0, 77], - [0, 78], - [0, 79], - [0, 80], - [0, 81], - [0, 82], - [0, 83], - [0, 84], - [0, 85], - [0, 86], - [0, 87], - [0, 88], - [0, 89], - [0, 90], - [0, 91], - [0, 92], - [0, 93], - [0, 94], - [0, 95], - [0, 96], - [0, 97], - [0, 98], - [0, 99], - [0, 100], - [0, 101], - [0, 102], - [0, 103], - [0, 104], - [0, 105], - [0, 106], - [0, 107], - [0, 108], - [0, 109], - [0, 110], - [0, 111], - [0, 112], - [0, 113], - [0, 114], - [0, 115], - [0, 116], - [0, 117], - [0, 118], - [0, 119], - [0, 120], - [0, 121], - [0, 122], - [0, 123], - [0, 124], - [0, 125], - [0, 126], - [0, 127], - [0, 128], - [0, 129], - [0, 130], - [0, 131], - [0, 132], - [0, 133], - [0, 134], - [0, 135], - [0, 136], - [0, 137], - [0, 138], - [0, 139], - [0, 140], - [0, 141], - [0, 142], - [0, 143], - [0, 144], - [0, 145], - [0, 146], - [0, 147], - [0, 148], - [0, 149], - [0, 150], - [0, 151], - [0, 152], - [0, 153], - [0, 154], - [0, 155], - [0, 156], - [0, 157], - [0, 158], - [0, 159], - [0, 160], - [0, 161], - [0, 162], - [0, 163], - [0, 164], - [0, 165], - [0, 166], - [0, 167], - [0, 168], - [0, 169], - [0, 170], - [0, 171], - [0, 172], - [0, 173], - [0, 174], - [0, 175], - [0, 176], - [0, 177], - [0, 178], - [0, 179], - [0, 180], - [0, 181], - [0, 182], - [0, 183], - [0, 184], - [0, 185], - [0, 186], - [0, 187], - [0, 188], - [0, 189], - [0, 190], - [0, 191], - [0, 192], - [0, 193], - [0, 194], - [0, 195], - [0, 196], - [0, 197], - [0, 198], - [0, 199], - [0, 200], - [0, 201], - [0, 202], - [0, 203], - [0, 204], - [0, 205], - [0, 206], - [0, 207], - [0, 208], - [0, 209], - [0, 210], - [0, 211], - [0, 212], - [0, 213], - [0, 214], - [0, 215], - [0, 216], - [0, 217], - [0, 218], - [0, 219], - [0, 220], - [0, 221], - [0, 222], - [0, 223], - [0, 224], - [0, 225], - [0, 226], - [0, 227], - [0, 228], - [0, 229], - [0, 230], - [0, 231], - [0, 232], - [0, 233], - [0, 234], - [0, 235], - [0, 236], - [0, 237], - [0, 238], - [0, 239], - [0, 240], - [0, 241], - [0, 242], - [0, 243], - [0, 244], - [0, 245], - [0, 246], - [0, 247], - [0, 248], - [0, 249], - [0, 250], - [0, 251], - [0, 252], - [0, 253], - [0, 254], - [0, 255], - [0, 256], - [0, 257], - [0, 258], - [0, 259], - [0, 260], - [0, 261], - [0, 262], - [0, 263], - [0, 264], - [0, 265], - [0, 266], - [0, 267], - [0, 268], - [0, 269], - [0, 270], - [0, 271], - [0, 272], - [0, 273], - [0, 274], - [0, 275], - [0, 276], - [0, 277], - [0, 278], - [0, 279], - [0, 280], - [0, 281], - [0, 282], - [0, 283], - [0, 284], - [0, 285], - [0, 286], - [0, 287], - [0, 288], - [0, 289], - [0, 290], - [0, 291], - [0, 292], - [0, 293], - [0, 294], - [0, 295], - [0, 296], - [0, 297], - [0, 298], - [0, 299], - [0, 300], - [0, 301], - [0, 302], - [0, 303], - [0, 304], - [0, 305], - [0, 306], - [0, 307], - [0, 308], - [0, 309], - [0, 310], - [0, 311], - [0, 312], - [0, 313], - [0, 314], - [0, 315], - [0, 316], - [0, 317], - [0, 318], - [0, 319], - [0, 320], - [0, 321], - [0, 322], - [0, 323], - [0, 324], - [0, 325], - [0, 326], - [0, 327], - [0, 328], - [0, 329], - [0, 330], - [0, 331], - [0, 332], - [0, 333], - [0, 334], - [0, 335], - [0, 336], - [0, 337], - [0, 338], - [0, 339], - [0, 340], - [0, 341], - [0, 342], - [0, 343], - [0, 344], - [0, 345], - [0, 346], - [0, 347], - [0, 348], - [0, 349], - [0, 350], - [0, 351], - [0, 352], - [0, 353], - [0, 354], - [0, 355], - [0, 356], - [0, 357], - [0, 358], - [0, 359], - [0, 360], - [0, 361], - [0, 362], - [0, 363], - [0, 364], - [0, 365], - [0, 366], - [0, 367], - [0, 368], - [0, 369], - [0, 370], - [0, 371], - [0, 372], - [0, 373], - [0, 374], - [0, 375], - [0, 376], - [0, 377], - [0, 378], - [0, 379], - [0, 380], - [0, 381], - [0, 382], - [0, 383], - [0, 384], - [0, 385], - [0, 386], - [0, 387], - [0, 388], - [0, 389], - [0, 390], - [0, 391], - [0, 392], - [0, 393], - [0, 394], - [0, 395], - [0, 396], - [0, 397], - [0, 398], - [0, 399], - [0, 400], - [0, 401], - [0, 402], - [0, 403], - [0, 404], - [0, 405], - [0, 406], - [0, 407], - [0, 408], - [0, 409], - [0, 410], - [0, 411], - [0, 412], - [0, 413], - [0, 414], - [0, 415], - [0, 416], - [0, 417], - [0, 418], - [0, 419], - [0, 420], - [0, 421], - [0, 422], - [0, 423], - [0, 424], - [0, 425], - [0, 426], - [0, 427], - [0, 428], - [0, 429], - [0, 430], - [0, 431], - [0, 432], - [0, 433], - [0, 434], - [0, 435], - [0, 436], - [0, 437], - [0, 438], - [0, 439], - [0, 440], - [0, 441], - [0, 442], - [0, 443], - [0, 444], - [0, 445], - [0, 446], - [0, 447], - [0, 448], - [0, 449], - [0, 450], - [0, 451], - [0, 452], - [0, 453], - [0, 454], - [0, 455], - [0, 456], - [0, 457], - [0, 458], - [0, 459], - [0, 460], - [0, 461], - [0, 462], - [0, 463], - [0, 464], - [0, 465], - [0, 466], - [0, 467], - [0, 468], - [0, 469], - [0, 470], - [0, 471], - [0, 472], - [0, 473], - [0, 474], - [0, 475], - [0, 476], - [0, 477], - [0, 478], - [0, 479], - [0, 480], - [0, 481], - [0, 482], - [0, 483], - [0, 484], - [0, 485], - [0, 486], - [0, 487], - [0, 488], - [0, 489], - [0, 490], - [0, 491], - [0, 492], - [0, 493], - [0, 494], - [0, 495], - [0, 496], - [0, 497], - [0, 498], - [0, 499], - [0, 500], - [1, 2], - [1, 3], - [1, 4], - [1, 5], - [1, 6], - [1, 7], - [1, 8], - [1, 9], - [1, 10], - [1, 11], - [1, 12], - [1, 13], - [1, 14], - [1, 15], - [1, 16], - [1, 17], - [1, 18], - [1, 19], - [1, 20], - [1, 21], - [1, 22], - [1, 23], - [1, 24], - [1, 25], - [1, 26], - [1, 27], - [1, 28], - [1, 29], - [1, 30], - [1, 31], - [1, 32], - [1, 33], - [1, 34], - [1, 35], - [1, 36], - [1, 37], - [1, 38], - [1, 39], - [1, 40], - [1, 41], - [1, 42], - [1, 43], - [1, 44], - [1, 45], - [1, 46], - [1, 47], - [1, 48], - [1, 49], - [1, 50], - [1, 51], - [1, 52], - [1, 53], - [1, 54], - [1, 55], - [1, 56], - [1, 57], - [1, 58], - [1, 59], - [1, 60], - [1, 61], - [1, 62], - [1, 63], - [1, 64], - [1, 65], - [1, 66], - [1, 67], - [1, 68], - [1, 69], - [1, 70], - [1, 71], - [1, 72], - [1, 73], - [1, 74], - [1, 75], - [1, 76], - [1, 77], - [1, 78], - [1, 79], - [1, 80], - [1, 81], - [1, 82], - [1, 83], - [1, 84], - [1, 85], - [1, 86], - [1, 87], - [1, 88], - [1, 89], - [1, 90], - [1, 91], - [1, 92], - [1, 93], - [1, 94], - [1, 95], - [1, 96], - [1, 97], - [1, 98], - [1, 99], - [1, 100], - [1, 101], - [1, 102], - [1, 103], - [1, 104], - [1, 105], - [1, 106], - [1, 107], - [1, 108], - [1, 109], - [1, 110], - [1, 111], - [1, 112], - [1, 113], - [1, 114], - [1, 115], - [1, 116], - [1, 117], - [1, 118], - [1, 119], - [1, 120], - [1, 121], - [1, 122], - [1, 123], - [1, 124], - [1, 125], - [1, 126], - [1, 127], - [1, 128], - [1, 129], - [1, 130], - [1, 131], - [1, 132], - [1, 133], - [1, 134], - [1, 135], - [1, 136], - [1, 137], - [1, 138], - [1, 139], - [1, 140], - [1, 141], - [1, 142], - [1, 143], - [1, 144], - [1, 145], - [1, 146], - [1, 147], - [1, 148], - [1, 149], - [1, 150], - [1, 151], - [1, 152], - [1, 153], - [1, 154], - [1, 155], - [1, 156], - [1, 157], - [1, 158], - [1, 159], - [1, 160], - [1, 161], - [1, 162], - [1, 163], - [1, 164], - [1, 165], - [1, 166], - [1, 167], - [1, 168], - [1, 169], - [1, 170], - [1, 171], - [1, 172], - [1, 173], - [1, 174], - [1, 175], - [1, 176], - [1, 177], - [1, 178], - [1, 179], - [1, 180], - [1, 181], - [1, 182], - [1, 183], - [1, 184], - [1, 185], - [1, 186], - [1, 187], - [1, 188], - [1, 189], - [1, 190], - [1, 191], - [1, 192], - [1, 193], - [1, 194], - [1, 195], - [1, 196], - [1, 197], - [1, 198], - [1, 199], - [1, 200], - [1, 201], - [1, 202], - [1, 203], - [1, 204], - [1, 205], - [1, 206], - [1, 207], - [1, 208], - [1, 209], - [1, 210], - [1, 211], - [1, 212], - [1, 213], - [1, 214], - [1, 215], - [1, 216], - [1, 217], - [1, 218], - [1, 219], - [1, 220], - [1, 221], - [1, 222], - [1, 223], - [1, 224], - [1, 225], - [1, 226], - [1, 227], - [1, 228], - [1, 229], - [1, 230], - [1, 231], - [1, 232], - [1, 233], - [1, 234], - [1, 235], - [1, 236], - [1, 237], - [1, 238], - [1, 239], - [1, 240], - [1, 241], - [1, 242], - [1, 243], - [1, 244], - [1, 245], - [1, 246], - [1, 247], - [1, 248], - [1, 249], - [1, 250], - [1, 251], - [1, 252], - [1, 253], - [1, 254], - [1, 255], - [1, 256], - [1, 257], - [1, 258], - [1, 259], - [1, 260], - [1, 261], - [1, 262], - [1, 263], - [1, 264], - [1, 265], - [1, 266], - [1, 267], - [1, 268], - [1, 269], - [1, 270], - [1, 271], - [1, 272], - [1, 273], - [1, 274], - [1, 275], - [1, 276], - [1, 277], - [1, 278], - [1, 279], - [1, 280], - [1, 281], - [1, 282], - [1, 283], - [1, 284], - [1, 285], - [1, 286], - [1, 287], - [1, 288], - [1, 289], - [1, 290], - [1, 291], - [1, 292], - [1, 293], - [1, 294], - [1, 295], - [1, 296], - [1, 297], - [1, 298], - [1, 299], - [1, 300], - [1, 301], - [1, 302], - [1, 303], - [1, 304], - [1, 305], - [1, 306], - [1, 307], - [1, 308], - [1, 309], - [1, 310], - [1, 311], - [1, 312], - [1, 313], - [1, 314], - [1, 315], - [1, 316], - [1, 317], - [1, 318], - [1, 319], - [1, 320], - [1, 321], - [1, 322], - [1, 323], - [1, 324], - [1, 325], - [1, 326], - [1, 327], - [1, 328], - [1, 329], - [1, 330], - [1, 331], - [1, 332], - [1, 333], - [1, 334], - [1, 335], - [1, 336], - [1, 337], - [1, 338], - [1, 339], - [1, 340], - [1, 341], - [1, 342], - [1, 343], - [1, 344], - [1, 345], - [1, 346], - [1, 347], - [1, 348], - [1, 349], - [1, 350], - [1, 351], - [1, 352], - [1, 353], - [1, 354], - [1, 355], - [1, 356], - [1, 357], - [1, 358], - [1, 359], - [1, 360], - [1, 361], - [1, 362], - [1, 363], - [1, 364], - [1, 365], - [1, 366], - [1, 367], - [1, 368], - [1, 369], - [1, 370], - [1, 371], - [1, 372], - [1, 373], - [1, 374], - [1, 375], - [1, 376], - [1, 377], - [1, 378], - [1, 379], - [1, 380], - [1, 381], - [1, 382], - [1, 383], - [1, 384], - [1, 385], - [1, 386], - [1, 387], - [1, 388], - [1, 389], - [1, 390], - [1, 391], - [1, 392], - [1, 393], - [1, 394], - [1, 395], - [1, 396], - [1, 397], - [1, 398], - [1, 399], - [1, 400], - [1, 401], - [1, 402], - [1, 403], - [1, 404], - [1, 405], - [1, 406], - [1, 407], - [1, 408], - [1, 409], - [1, 410], - [1, 411], - [1, 412], - [1, 413], - [1, 414], - [1, 415], - [1, 416], - [1, 417], - [1, 418], - [1, 419], - [1, 420], - [1, 421], - [1, 422], - [1, 423], - [1, 424], - [1, 425], - [1, 426], - [1, 427], - [1, 428], - [1, 429], - [1, 430], - [1, 431], - [1, 432], - [1, 433], - [1, 434], - [1, 435], - [1, 436], - [1, 437], - [1, 438], - [1, 439], - [1, 440], - [1, 441], - [1, 442], - [1, 443], - [1, 444], - [1, 445], - [1, 446], - [1, 447], - [1, 448], - [1, 449], - [1, 450], - [1, 451], - [1, 452], - [1, 453], - [1, 454], - [1, 455], - [1, 456], - [1, 457], - [1, 458], - [1, 459], - [1, 460], - [1, 461], - [1, 462], - [1, 463], - [1, 464], - [1, 465], - [1, 466], - [1, 467], - [1, 468], - [1, 469], - [1, 470], - [1, 471], - [1, 472], - [1, 473], - [1, 474], - [1, 475], - [1, 476], - [1, 477], - [1, 478], - [1, 479], - [1, 480], - [1, 481], - [1, 482], - [1, 483], - [1, 484], - [1, 485], - [1, 486], - [1, 487], - [1, 488], - [1, 489], - [1, 490], - [1, 491], - [1, 492], - [1, 493], - [1, 494], - [1, 495], - [1, 496], - [1, 497], - [1, 498], - [1, 499], - [1, 500], - [2, 2], - [2, 3], - [2, 4], - [2, 5], - [2, 6], - [2, 7], - [2, 8], - [2, 9], - [2, 10], - [2, 11], - [2, 12], - [2, 13], - [2, 14], - [2, 15], - [2, 16], - [2, 17], - [2, 18], - [2, 19], - [2, 20], - [2, 21], - [2, 22], - [2, 23], - [2, 24], - [2, 25], - [2, 26], - [2, 27], - [2, 28], - [2, 29], - [2, 30], - [2, 31], - [2, 32], - [2, 33], - [2, 34], - [2, 35], - [2, 36], - [2, 37], - [2, 38], - [2, 39], - [2, 40], - [2, 41], - [2, 42], - [2, 43], - [2, 44], - [2, 45], - [2, 46], - [2, 47], - [2, 48], - [2, 49], - [2, 50], - [2, 51], - [2, 52], - [2, 53], - [2, 54], - [2, 55], - [2, 56], - [2, 57], - [2, 58], - [2, 59], - [2, 60], - [2, 61], - [2, 62], - [2, 63], - [2, 64], - [2, 65], - [2, 66], - [2, 67], - [2, 68], - [2, 69], - [2, 70], - [2, 71], - [2, 72], - [2, 73], - [2, 74], - [2, 75], - [2, 76], - [2, 77], - [2, 78], - [2, 79], - [2, 80], - [2, 81], - [2, 82], - [2, 83], - [2, 84], - [2, 85], - [2, 86], - [2, 87], - [2, 88], - [2, 89], - [2, 90], - [2, 91], - [2, 92], - [2, 93], - [2, 94], - [2, 95], - [2, 96], - [2, 97], - [2, 98], - [2, 99], - [2, 100], - [2, 101], - [2, 102], - [2, 103], - [2, 104], - [2, 105], - [2, 106], - [2, 107], - [2, 108], - [2, 109], - [2, 110], - [2, 111], - [2, 112], - [2, 113], - [2, 114], - [2, 115], - [2, 116], - [2, 117], - [2, 118], - [2, 119], - [2, 120], - [2, 121], - [2, 122], - [2, 123], - [2, 124], - [2, 125], - [2, 126], - [2, 127], - [2, 128], - [2, 129], - [2, 130], - [2, 131], - [2, 132], - [2, 133], - [2, 134], - [2, 135], - [2, 136], - [2, 137], - [2, 138], - [2, 139], - [2, 140], - [2, 141], - [2, 142], - [2, 143], - [2, 144], - [2, 145], - [2, 146], - [2, 147], - [2, 148], - [2, 149], - [2, 150], - [2, 151], - [2, 152], - [2, 153], - [2, 154], - [2, 155], - [2, 156], - [2, 157], - [2, 158], - [2, 159], - [2, 160], - [2, 161], - [2, 162], - [2, 163], - [2, 164], - [2, 165], - [2, 166], - [2, 167], - [2, 168], - [2, 169], - [2, 170], - [2, 171], - [2, 172], - [2, 173], - [2, 174], - [2, 175], - [2, 176], - [2, 177], - [2, 178], - [2, 179], - [2, 180], - [2, 181], - [2, 182], - [2, 183], - [2, 184], - [2, 185], - [2, 186], - [2, 187], - [2, 188], - [2, 189], - [2, 190], - [2, 191], - [2, 192], - [2, 193], - [2, 194], - [2, 195], - [2, 196], - [2, 197], - [2, 198], - [2, 199], - [2, 200], - [2, 201], - [2, 202], - [2, 203], - [2, 204], - [2, 205], - [2, 206], - [2, 207], - [2, 208], - [2, 209], - [2, 210], - [2, 211], - [2, 212], - [2, 213], - [2, 214], - [2, 215], - [2, 216], - [2, 217], - [2, 218], - [2, 219], - [2, 220], - [2, 221], - [2, 222], - [2, 223], - [2, 224], - [2, 225], - [2, 226], - [2, 227], - [2, 228], - [2, 229], - [2, 230], - [2, 231], - [2, 232], - [2, 233], - [2, 234], - [2, 235], - [2, 236], - [2, 237], - [2, 238], - [2, 239], - [2, 240], - [2, 241], - [2, 242], - [2, 243], - [2, 244], - [2, 245], - [2, 246], - [2, 247], - [2, 248], - [2, 249], - [2, 250], - [2, 251], - [2, 252], - [2, 253], - [2, 254], - [2, 255], - [2, 256], - [2, 257], - [2, 258], - [2, 259], - [2, 260], - [2, 261], - [2, 262], - [2, 263], - [2, 264], - [2, 265], - [2, 266], - [2, 267], - [2, 268], - [2, 269], - [2, 270], - [2, 271], - [2, 272], - [2, 273], - [2, 274], - [2, 275], - [2, 276], - [2, 277], - [2, 278], - [2, 279], - [2, 280], - [2, 281], - [2, 282], - [2, 283], - [2, 284], - [2, 285], - [2, 286], - [2, 287], - [2, 288], - [2, 289], - [2, 290], - [2, 291], - [2, 292], - [2, 293], - [2, 294], - [2, 295], - [2, 296], - [2, 297], - [2, 298], - [2, 299], - [2, 300], - [2, 301], - [2, 302], - [2, 303], - [2, 304], - [2, 305], - [2, 306], - [2, 307], - [2, 308], - [2, 309], - [2, 310], - [2, 311], - [2, 312], - [2, 313], - [2, 314], - [2, 315], - [2, 316], - [2, 317], - [2, 318], - [2, 319], - [2, 320], - [2, 321], - [2, 322], - [2, 323], - [2, 324], - [2, 325], - [2, 326], - [2, 327], - [2, 328], - [2, 329], - [2, 330], - [2, 331], - [2, 332], - [2, 333], - [2, 334], - [2, 335], - [2, 336], - [2, 337], - [2, 338], - [2, 339], - [2, 340], - [2, 341], - [2, 342], - [2, 343], - [2, 344], - [2, 345], - [2, 346], - [2, 347], - [2, 348], - [2, 349], - [2, 350], - [2, 351], - [2, 352], - [2, 353], - [2, 354], - [2, 355], - [2, 356], - [2, 357], - [2, 358], - [2, 359], - [2, 360], - [2, 361], - [2, 362], - [2, 363], - [2, 364], - [2, 365], - [2, 366], - [2, 367], - [2, 368], - [2, 369], - [2, 370], - [2, 371], - [2, 372], - [2, 373], - [2, 374], - [2, 375], - [2, 376], - [2, 377], - [2, 378], - [2, 379], - [2, 380], - [2, 381], - [2, 382], - [2, 383], - [2, 384], - [2, 385], - [2, 386], - [2, 387], - [2, 388], - [2, 389], - [2, 390], - [2, 391], - [2, 392], - [2, 393], - [2, 394], - [2, 395], - [2, 396], - [2, 397], - [2, 398], - [2, 399], - [2, 400], - [2, 401], - [2, 402], - [2, 403], - [2, 404], - [2, 405], - [2, 406], - [2, 407], - [2, 408], - [2, 409], - [2, 410], - [2, 411], - [2, 412], - [2, 413], - [2, 414], - [2, 415], - [2, 416], - [2, 417], - [2, 418], - [2, 419], - [2, 420], - [2, 421], - [2, 422], - [2, 423], - [2, 424], - [2, 425], - [2, 426], - [2, 427], - [2, 428], - [2, 429], - [2, 430], - [2, 431], - [2, 432], - [2, 433], - [2, 434], - [2, 435], - [2, 436], - [2, 437], - [2, 438], - [2, 439], - [2, 440], - [2, 441], - [2, 442], - [2, 443], - [2, 444], - [2, 445], - [2, 446], - [2, 447], - [2, 448], - [2, 449], - [2, 450], - [2, 451], - [2, 452], - [2, 453], - [2, 454], - [2, 455], - [2, 456], - [2, 457], - [2, 458], - [2, 459], - [2, 460], - [2, 461], - [2, 462], - [2, 463], - [2, 464], - [2, 465], - [2, 466], - [2, 467], - [2, 468], - [2, 469], - [2, 470], - [2, 471], - [2, 472], - [2, 473], - [2, 474], - [2, 475], - [2, 476], - [2, 477], - [2, 478], - [2, 479], - [2, 480], - [2, 481], - [2, 482], - [2, 483], - [2, 484], - [2, 485], - [2, 486], - [2, 487], - [2, 488], - [2, 489], - [2, 490], - [2, 491], - [2, 492], - [2, 493], - [2, 494], - [2, 495], - [2, 496], - [2, 497], - [2, 498], - [2, 499], - [2, 500], - [3, 2], - [3, 3], - [3, 4], - [3, 5], - [3, 6], - [3, 7], - [3, 8], - [3, 9], - [3, 10], - [3, 11], - [3, 12], - [3, 13], - [3, 14], - [3, 15], - [3, 16], - [3, 17], - [3, 18], - [3, 19], - [3, 20], - [3, 21], - [3, 22], - [3, 23], - [3, 24], - [3, 25], - [3, 26], - [3, 27], - [3, 28], - [3, 29], - [3, 30], - [3, 31], - [3, 32], - [3, 33], - [3, 34], - [3, 35], - [3, 36], - [3, 37], - [3, 38], - [3, 39], - [3, 40], - [3, 41], - [3, 42], - [3, 43], - [3, 44], - [3, 45], - [3, 46], - [3, 47], - [3, 48], - [3, 49], - [3, 50], - [3, 51], - [3, 52], - [3, 53], - [3, 54], - [3, 55], - [3, 56], - [3, 57], - [3, 58], - [3, 59], - [3, 60], - [3, 61], - [3, 62], - [3, 63], - [3, 64], - [3, 65], - [3, 66], - [3, 67], - [3, 68], - [3, 69], - [3, 70], - [3, 71], - [3, 72], - [3, 73], - [3, 74], - [3, 75], - [3, 76], - [3, 77], - [3, 78], - [3, 79], - [3, 80], - [3, 81], - [3, 82], - [3, 83], - [3, 84], - [3, 85], - [3, 86], - [3, 87], - [3, 88], - [3, 89], - [3, 90], - [3, 91], - [3, 92], - [3, 93], - [3, 94], - [3, 95], - [3, 96], - [3, 97], - [3, 98], - [3, 99], - [3, 100], - [3, 101], - [3, 102], - [3, 103], - [3, 104], - [3, 105], - [3, 106], - [3, 107], - [3, 108], - [3, 109], - [3, 110], - [3, 111], - [3, 112], - [3, 113], - [3, 114], - [3, 115], - [3, 116], - [3, 117], - [3, 118], - [3, 119], - [3, 120], - [3, 121], - [3, 122], - [3, 123], - [3, 124], - [3, 125], - [3, 126], - [3, 127], - [3, 128], - [3, 129], - [3, 130], - [3, 131], - [3, 132], - [3, 133], - [3, 134], - [3, 135], - [3, 136], - [3, 137], - [3, 138], - [3, 139], - [3, 140], - [3, 141], - [3, 142], - [3, 143], - [3, 144], - [3, 145], - [3, 146], - [3, 147], - [3, 148], - [3, 149], - [3, 150], - [3, 151], - [3, 152], - [3, 153], - [3, 154], - [3, 155], - [3, 156], - [3, 157], - [3, 158], - [3, 159], - [3, 160], - [3, 161], - [3, 162], - [3, 163], - [3, 164], - [3, 165], - [3, 166], - [3, 167], - [3, 168], - [3, 169], - [3, 170], - [3, 171], - [3, 172], - [3, 173], - [3, 174], - [3, 175], - [3, 176], - [3, 177], - [3, 178], - [3, 179], - [3, 180], - [3, 181], - [3, 182], - [3, 183], - [3, 184], - [3, 185], - [3, 186], - [3, 187], - [3, 188], - [3, 189], - [3, 190], - [3, 191], - [3, 192], - [3, 193], - [3, 194], - [3, 195], - [3, 196], - [3, 197], - [3, 198], - [3, 199], - [3, 200], - [3, 201], - [3, 202], - [3, 203], - [3, 204], - [3, 205], - [3, 206], - [3, 207], - [3, 208], - [3, 209], - [3, 210], - [3, 211], - [3, 212], - [3, 213], - [3, 214], - [3, 215], - [3, 216], - [3, 217], - [3, 218], - [3, 219], - [3, 220], - [3, 221], - [3, 222], - [3, 223], - [3, 224], - [3, 225], - [3, 226], - [3, 227], - [3, 228], - [3, 229], - [3, 230], - [3, 231], - [3, 232], - [3, 233], - [3, 234], - [3, 235], - [3, 236], - [3, 237], - [3, 238], - [3, 239], - [3, 240], - [3, 241], - [3, 242], - [3, 243], - [3, 244], - [3, 245], - [3, 246], - [3, 247], - [3, 248], - [3, 249], - [3, 250], - [3, 251], - [3, 252], - [3, 253], - [3, 254], - [3, 255], - [3, 256], - [3, 257], - [3, 258], - [3, 259], - [3, 260], - [3, 261], - [3, 262], - [3, 263], - [3, 264], - [3, 265], - [3, 266], - [3, 267], - [3, 268], - [3, 269], - [3, 270], - [3, 271], - [3, 272], - [3, 273], - [3, 274], - [3, 275], - [3, 276], - [3, 277], - [3, 278], - [3, 279], - [3, 280], - [3, 281], - [3, 282], - [3, 283], - [3, 284], - [3, 285], - [3, 286], - [3, 287], - [3, 288], - [3, 289], - [3, 290], - [3, 291], - [3, 292], - [3, 293], - [3, 294], - [3, 295], - [3, 296], - [3, 297], - [3, 298], - [3, 299], - [3, 300], - [3, 301], - [3, 302], - [3, 303], - [3, 304], - [3, 305], - [3, 306], - [3, 307], - [3, 308], - [3, 309], - [3, 310], - [3, 311], - [3, 312], - [3, 313], - [3, 314], - [3, 315], - [3, 316], - [3, 317], - [3, 318], - [3, 319], - [3, 320], - [3, 321], - [3, 322], - [3, 323], - [3, 324], - [3, 325], - [3, 326], - [3, 327], - [3, 328], - [3, 329], - [3, 330], - [3, 331], - [3, 332], - [3, 333], - [3, 334], - [3, 335], - [3, 336], - [3, 337], - [3, 338], - [3, 339], - [3, 340], - [3, 341], - [3, 342], - [3, 343], - [3, 344], - [3, 345], - [3, 346], - [3, 347], - [3, 348], - [3, 349], - [3, 350], - [3, 351], - [3, 352], - [3, 353], - [3, 354], - [3, 355], - [3, 356], - [3, 357], - [3, 358], - [3, 359], - [3, 360], - [3, 361], - [3, 362], - [3, 363], - [3, 364], - [3, 365], - [3, 366], - [3, 367], - [3, 368], - [3, 369], - [3, 370], - [3, 371], - [3, 372], - [3, 373], - [3, 374], - [3, 375], - [3, 376], - [3, 377], - [3, 378], - [3, 379], - [3, 380], - [3, 381], - [3, 382], - [3, 383], - [3, 384], - [3, 385], - [3, 386], - [3, 387], - [3, 388], - [3, 389], - [3, 390], - [3, 391], - [3, 392], - [3, 393], - [3, 394], - [3, 395], - [3, 396], - [3, 397], - [3, 398], - [3, 399], - [3, 400], - [3, 401], - [3, 402], - [3, 403], - [3, 404], - [3, 405], - [3, 406], - [3, 407], - [3, 408], - [3, 409], - [3, 410], - [3, 411], - [3, 412], - [3, 413], - [3, 414], - [3, 415], - [3, 416], - [3, 417], - [3, 418], - [3, 419], - [3, 420], - [3, 421], - [3, 422], - [3, 423], - [3, 424], - [3, 425], - [3, 426], - [3, 427], - [3, 428], - [3, 429], - [3, 430], - [3, 431], - [3, 432], - [3, 433], - [3, 434], - [3, 435], - [3, 436], - [3, 437], - [3, 438], - [3, 439], - [3, 440], - [3, 441], - [3, 442], - [3, 443], - [3, 444], - [3, 445], - [3, 446], - [3, 447], - [3, 448], - [3, 449], - [3, 450], - [3, 451], - [3, 452], - [3, 453], - [3, 454], - [3, 455], - [3, 456], - [3, 457], - [3, 458], - [3, 459], - [3, 460], - [3, 461], - [3, 462], - [3, 463], - [3, 464], - [3, 465], - [3, 466], - [3, 467], - [3, 468], - [3, 469], - [3, 470], - [3, 471], - [3, 472], - [3, 473], - [3, 474], - [3, 475], - [3, 476], - [3, 477], - [3, 478], - [3, 479], - [3, 480], - [3, 481], - [3, 482], - [3, 483], - [3, 484], - [3, 485], - [3, 486], - [3, 487], - [3, 488], - [3, 489], - [3, 490], - [3, 491], - [3, 492], - [3, 493], - [3, 494], - [3, 495], - [3, 496], - [3, 497], - [3, 498], - [3, 499], - [3, 500], - [4, 2], - [4, 3], - [4, 4], - [4, 5], - [4, 6], - [4, 7], - [4, 8], - [4, 9], - [4, 10], - [4, 11], - [4, 12], - [4, 13], - [4, 14], - [4, 15], - [4, 16], - [4, 17], - [4, 18], - [4, 19], - [4, 20], - [4, 21], - [4, 22], - [4, 23], - [4, 24], - [4, 25], - [4, 26], - [4, 27], - [4, 28], - [4, 29], - [4, 30], - [4, 31], - [4, 32], - [4, 33], - [4, 34], - [4, 35], - [4, 36], - [4, 37], - [4, 38], - [4, 39], - [4, 40], - [4, 41], - [4, 42], - [4, 43], - [4, 44], - [4, 45], - [4, 46], - [4, 47], - [4, 48], - [4, 49], - [4, 50], - [4, 51], - [4, 52], - [4, 53], - [4, 54], - [4, 55], - [4, 56], - [4, 57], - [4, 58], - [4, 59], - [4, 60], - [4, 61], - [4, 62], - [4, 63], - [4, 64], - [4, 65], - [4, 66], - [4, 67], - [4, 68], - [4, 69], - [4, 70], - [4, 71], - [4, 72], - [4, 73], - [4, 74], - [4, 75], - [4, 76], - [4, 77], - [4, 78], - [4, 79], - [4, 80], - [4, 81], - [4, 82], - [4, 83], - [4, 84], - [4, 85], - [4, 86], - [4, 87], - [4, 88], - [4, 89], - [4, 90], - [4, 91], - [4, 92], - [4, 93], - [4, 94], - [4, 95], - [4, 96], - [4, 97], - [4, 98], - [4, 99], - [4, 100], - [4, 101], - [4, 102], - [4, 103], - [4, 104], - [4, 105], - [4, 106], - [4, 107], - [4, 108], - [4, 109], - [4, 110], - [4, 111], - [4, 112], - [4, 113], - [4, 114], - [4, 115], - [4, 116], - [4, 117], - [4, 118], - [4, 119], - [4, 120], - [4, 121], - [4, 122], - [4, 123], - [4, 124], - [4, 125], - [4, 126], - [4, 127], - [4, 128], - [4, 129], - [4, 130], - [4, 131], - [4, 132], - [4, 133], - [4, 134], - [4, 135], - [4, 136], - [4, 137], - [4, 138], - [4, 139], - [4, 140], - [4, 141], - [4, 142], - [4, 143], - [4, 144], - [4, 145], - [4, 146], - [4, 147], - [4, 148], - [4, 149], - [4, 150], - [4, 151], - [4, 152], - [4, 153], - [4, 154], - [4, 155], - [4, 156], - [4, 157], - [4, 158], - [4, 159], - [4, 160], - [4, 161], - [4, 162], - [4, 163], - [4, 164], - [4, 165], - [4, 166], - [4, 167], - [4, 168], - [4, 169], - [4, 170], - [4, 171], - [4, 172], - [4, 173], - [4, 174], - [4, 175], - [4, 176], - [4, 177], - [4, 178], - [4, 179], - [4, 180], - [4, 181], - [4, 182], - [4, 183], - [4, 184], - [4, 185], - [4, 186], - [4, 187], - [4, 188], - [4, 189], - [4, 190], - [4, 191], - [4, 192], - [4, 193], - [4, 194], - [4, 195], - [4, 196], - [4, 197], - [4, 198], - [4, 199], - [4, 200], - [4, 201], - [4, 202], - [4, 203], - [4, 204], - [4, 205], - [4, 206], - [4, 207], - [4, 208], - [4, 209], - [4, 210], - [4, 211], - [4, 212], - [4, 213], - [4, 214], - [4, 215], - [4, 216], - [4, 217], - [4, 218], - [4, 219], - [4, 220], - [4, 221], - [4, 222], - [4, 223], - [4, 224], - [4, 225], - [4, 226], - [4, 227], - [4, 228], - [4, 229], - [4, 230], - [4, 231], - [4, 232], - [4, 233], - [4, 234], - [4, 235], - [4, 236], - [4, 237], - [4, 238], - [4, 239], - [4, 240], - [4, 241], - [4, 242], - [4, 243], - [4, 244], - [4, 245], - [4, 246], - [4, 247], - [4, 248], - [4, 249], - [4, 250], - [4, 251], - [4, 252], - [4, 253], - [4, 254], - [4, 255], - [4, 256], - [4, 257], - [4, 258], - [4, 259], - [4, 260], - [4, 261], - [4, 262], - [4, 263], - [4, 264], - [4, 265], - [4, 266], - [4, 267], - [4, 268], - [4, 269], - [4, 270], - [4, 271], - [4, 272], - [4, 273], - [4, 274], - [4, 275], - [4, 276], - [4, 277], - [4, 278], - [4, 279], - [4, 280], - [4, 281], - [4, 282], - [4, 283], - [4, 284], - [4, 285], - [4, 286], - [4, 287], - [4, 288], - [4, 289], - [4, 290], - [4, 291], - [4, 292], - [4, 293], - [4, 294], - [4, 295], - [4, 296], - [4, 297], - [4, 298], - [4, 299], - [4, 300], - [4, 301], - [4, 302], - [4, 303], - [4, 304], - [4, 305], - [4, 306], - [4, 307], - [4, 308], - [4, 309], - [4, 310], - [4, 311], - [4, 312], - [4, 313], - [4, 314], - [4, 315], - [4, 316], - [4, 317], - [4, 318], - [4, 319], - [4, 320], - [4, 321], - [4, 322], - [4, 323], - [4, 324], - [4, 325], - [4, 326], - [4, 327], - [4, 328], - [4, 329], - [4, 330], - [4, 331], - [4, 332], - [4, 333], - [4, 334], - [4, 335], - [4, 336], - [4, 337], - [4, 338], - [4, 339], - [4, 340], - [4, 341], - [4, 342], - [4, 343], - [4, 344], - [4, 345], - [4, 346], - [4, 347], - [4, 348], - [4, 349], - [4, 350], - [4, 351], - [4, 352], - [4, 353], - [4, 354], - [4, 355], - [4, 356], - [4, 357], - [4, 358], - [4, 359], - [4, 360], - [4, 361], - [4, 362], - [4, 363], - [4, 364], - [4, 365], - [4, 366], - [4, 367], - [4, 368], - [4, 369], - [4, 370], - [4, 371], - [4, 372], - [4, 373], - [4, 374], - [4, 375], - [4, 376], - [4, 377], - [4, 378], - [4, 379], - [4, 380], - [4, 381], - [4, 382], - [4, 383], - [4, 384], - [4, 385], - [4, 386], - [4, 387], - [4, 388], - [4, 389], - [4, 390], - [4, 391], - [4, 392], - [4, 393], - [4, 394], - [4, 395], - [4, 396], - [4, 397], - [4, 398], - [4, 399], - [4, 400], - [4, 401], - [4, 402], - [4, 403], - [4, 404], - [4, 405], - [4, 406], - [4, 407], - [4, 408], - [4, 409], - [4, 410], - [4, 411], - [4, 412], - [4, 413], - [4, 414], - [4, 415], - [4, 416], - [4, 417], - [4, 418], - [4, 419], - [4, 420], - [4, 421], - [4, 422], - [4, 423], - [4, 424], - [4, 425], - [4, 426], - [4, 427], - [4, 428], - [4, 429], - [4, 430], - [4, 431], - [4, 432], - [4, 433], - [4, 434], - [4, 435], - [4, 436], - [4, 437], - [4, 438], - [4, 439], - [4, 440], - [4, 441], - [4, 442], - [4, 443], - [4, 444], - [4, 445], - [4, 446], - [4, 447], - [4, 448], - [4, 449], - [4, 450], - [4, 451], - [4, 452], - [4, 453], - [4, 454], - [4, 455], - [4, 456], - [4, 457], - [4, 458], - [4, 459], - [4, 460], - [4, 461], - [4, 462], - [4, 463], - [4, 464], - [4, 465], - [4, 466], - [4, 467], - [4, 468], - [4, 469], - [4, 470], - [4, 471], - [4, 472], - [4, 473], - [4, 474], - [4, 475], - [4, 476], - [4, 477], - [4, 478], - [4, 479], - [4, 480], - [4, 481], - [4, 482], - [4, 483], - [4, 484], - [4, 485], - [4, 486], - [4, 487], - [4, 488], - [4, 489], - [4, 490], - [4, 491], - [4, 492], - [4, 493], - [4, 494], - [4, 495], - [4, 496], - [4, 497], - [4, 498], - [4, 499], - [4, 500], - [5, 2], - [5, 3], - [5, 4], - [5, 5], - [5, 6], - [5, 7], - [5, 8], - [5, 9], - [5, 10], - [5, 11], - [5, 12], - [5, 13], - [5, 14], - [5, 15], - [5, 16], - [5, 17], - [5, 18], - [5, 19], - [5, 20], - [5, 21], - [5, 22], - [5, 23], - [5, 24], - [5, 25], - [5, 26], - [5, 27], - [5, 28], - [5, 29], - [5, 30], - [5, 31], - [5, 32], - [5, 33], - [5, 34], - [5, 35], - [5, 36], - [5, 37], - [5, 38], - [5, 39], - [5, 40], - [5, 41], - [5, 42], - [5, 43], - [5, 44], - [5, 45], - [5, 46], - [5, 47], - [5, 48], - [5, 49], - [5, 50], - [5, 51], - [5, 52], - [5, 53], - [5, 54], - [5, 55], - [5, 56], - [5, 57], - [5, 58], - [5, 59], - [5, 60], - [5, 61], - [5, 62], - [5, 63], - [5, 64], - [5, 65], - [5, 66], - [5, 67], - [5, 68], - [5, 69], - [5, 70], - [5, 71], - [5, 72], - [5, 73], - [5, 74], - [5, 75], - [5, 76], - [5, 77], - [5, 78], - [5, 79], - [5, 80], - [5, 81], - [5, 82], - [5, 83], - [5, 84], - [5, 85], - [5, 86], - [5, 87], - [5, 88], - [5, 89], - [5, 90], - [5, 91], - [5, 92], - [5, 93], - [5, 94], - [5, 95], - [5, 96], - [5, 97], - [5, 98], - [5, 99], - [5, 100], - [5, 101], - [5, 102], - [5, 103], - [5, 104], - [5, 105], - [5, 106], - [5, 107], - [5, 108], - [5, 109], - [5, 110], - [5, 111], - [5, 112], - [5, 113], - [5, 114], - [5, 115], - [5, 116], - [5, 117], - [5, 118], - [5, 119], - [5, 120], - [5, 121], - [5, 122], - [5, 123], - [5, 124], - [5, 125], - [5, 126], - [5, 127], - [5, 128], - [5, 129], - [5, 130], - [5, 131], - [5, 132], - [5, 133], - [5, 134], - [5, 135], - [5, 136], - [5, 137], - [5, 138], - [5, 139], - [5, 140], - [5, 141], - [5, 142], - [5, 143], - [5, 144], - [5, 145], - [5, 146], - [5, 147], - [5, 148], - [5, 149], - [5, 150], - [5, 151], - [5, 152], - [5, 153], - [5, 154], - [5, 155], - [5, 156], - [5, 157], - [5, 158], - [5, 159], - [5, 160], - [5, 161], - [5, 162], - [5, 163], - [5, 164], - [5, 165], - [5, 166], - [5, 167], - [5, 168], - [5, 169], - [5, 170], - [5, 171], - [5, 172], - [5, 173], - [5, 174], - [5, 175], - [5, 176], - [5, 177], - [5, 178], - [5, 179], - [5, 180], - [5, 181], - [5, 182], - [5, 183], - [5, 184], - [5, 185], - [5, 186], - [5, 187], - [5, 188], - [5, 189], - [5, 190], - [5, 191], - [5, 192], - [5, 193], - [5, 194], - [5, 195], - [5, 196], - [5, 197], - [5, 198], - [5, 199], - [5, 200], - [5, 201], - [5, 202], - [5, 203], - [5, 204], - [5, 205], - [5, 206], - [5, 207], - [5, 208], - [5, 209], - [5, 210], - [5, 211], - [5, 212], - [5, 213], - [5, 214], - [5, 215], - [5, 216], - [5, 217], - [5, 218], - [5, 219], - [5, 220], - [5, 221], - [5, 222], - [5, 223], - [5, 224], - [5, 225], - [5, 226], - [5, 227], - [5, 228], - [5, 229], - [5, 230], - [5, 231], - [5, 232], - [5, 233], - [5, 234], - [5, 235], - [5, 236], - [5, 237], - [5, 238], - [5, 239], - [5, 240], - [5, 241], - [5, 242], - [5, 243], - [5, 244], - [5, 245], - [5, 246], - [5, 247], - [5, 248], - [5, 249], - [5, 250], - [5, 251], - [5, 252], - [5, 253], - [5, 254], - [5, 255], - [5, 256], - [5, 257], - [5, 258], - [5, 259], - [5, 260], - [5, 261], - [5, 262], - [5, 263], - [5, 264], - [5, 265], - [5, 266], - [5, 267], - [5, 268], - [5, 269], - [5, 270], - [5, 271], - [5, 272], - [5, 273], - [5, 274], - [5, 275], - [5, 276], - [5, 277], - [5, 278], - [5, 279], - [5, 280], - [5, 281], - [5, 282], - [5, 283], - [5, 284], - [5, 285], - [5, 286], - [5, 287], - [5, 288], - [5, 289], - [5, 290], - [5, 291], - [5, 292], - [5, 293], - [5, 294], - [5, 295], - [5, 296], - [5, 297], - [5, 298], - [5, 299], - [5, 300], - [5, 301], - [5, 302], - [5, 303], - [5, 304], - [5, 305], - [5, 306], - [5, 307], - [5, 308], - [5, 309], - [5, 310], - [5, 311], - [5, 312], - [5, 313], - [5, 314], - [5, 315], - [5, 316], - [5, 317], - [5, 318], - [5, 319], - [5, 320], - [5, 321], - [5, 322], - [5, 323], - [5, 324], - [5, 325], - [5, 326], - [5, 327], - [5, 328], - [5, 329], - [5, 330], - [5, 331], - [5, 332], - [5, 333], - [5, 334], - [5, 335], - [5, 336], - [5, 337], - [5, 338], - [5, 339], - [5, 340], - [5, 341], - [5, 342], - [5, 343], - [5, 344], - [5, 345], - [5, 346], - [5, 347], - [5, 348], - [5, 349], - [5, 350], - [5, 351], - [5, 352], - [5, 353], - [5, 354], - [5, 355], - [5, 356], - [5, 357], - [5, 358], - [5, 359], - [5, 360], - [5, 361], - [5, 362], - [5, 363], - [5, 364], - [5, 365], - [5, 366], - [5, 367], - [5, 368], - [5, 369], - [5, 370], - [5, 371], - [5, 372], - [5, 373], - [5, 374], - [5, 375], - [5, 376], - [5, 377], - [5, 378], - [5, 379], - [5, 380], - [5, 381], - [5, 382], - [5, 383], - [5, 384], - [5, 385], - [5, 386], - [5, 387], - [5, 388], - [5, 389], - [5, 390], - [5, 391], - [5, 392], - [5, 393], - [5, 394], - [5, 395], - [5, 396], - [5, 397], - [5, 398], - [5, 399], - [5, 400], - [5, 401], - [5, 402], - [5, 403], - [5, 404], - [5, 405], - [5, 406], - [5, 407], - [5, 408], - [5, 409], - [5, 410], - [5, 411], - [5, 412], - [5, 413], - [5, 414], - [5, 415], - [5, 416], - [5, 417], - [5, 418], - [5, 419], - [5, 420], - [5, 421], - [5, 422], - [5, 423], - [5, 424], - [5, 425], - [5, 426], - [5, 427], - [5, 428], - [5, 429], - [5, 430], - [5, 431], - [5, 432], - [5, 433], - [5, 434], - [5, 435], - [5, 436], - [5, 437], - [5, 438], - [5, 439], - [5, 440], - [5, 441], - [5, 442], - [5, 443], - [5, 444], - [5, 445], - [5, 446], - [5, 447], - [5, 448], - [5, 449], - [5, 450], - [5, 451], - [5, 452], - [5, 453], - [5, 454], - [5, 455], - [5, 456], - [5, 457], - [5, 458], - [5, 459], - [5, 460], - [5, 461], - [5, 462], - [5, 463], - [5, 464], - [5, 465], - [5, 466], - [5, 467], - [5, 468], - [5, 469], - [5, 470], - [5, 471], - [5, 472], - [5, 473], - [5, 474], - [5, 475], - [5, 476], - [5, 477], - [5, 478], - [5, 479], - [5, 480], - [5, 481], - [5, 482], - [5, 483], - [5, 484], - [5, 485], - [5, 486], - [5, 487], - [5, 488], - [5, 489], - [5, 490], - [5, 491], - [5, 492], - [5, 493], - [5, 494], - [5, 495], - [5, 496], - [5, 497], - [5, 498], - [5, 499], - [5, 500], - [6, 2], - [6, 3], - [6, 4], - [6, 5], - [6, 6], - [6, 7], - [6, 8], - [6, 9], - [6, 10], - [6, 11], - [6, 12], - [6, 13], - [6, 14], - [6, 15], - [6, 16], - [6, 17], - [6, 18], - [6, 19], - [6, 20], - [6, 21], - [6, 22], - [6, 23], - [6, 24], - [6, 25], - [6, 26], - [6, 27], - [6, 28], - [6, 29], - [6, 30], - [6, 31], - [6, 32], - [6, 33], - [6, 34], - [6, 35], - [6, 36], - [6, 37], - [6, 38], - [6, 39], - [6, 40], - [6, 41], - [6, 42], - [6, 43], - [6, 44], - [6, 45], - [6, 46], - [6, 47], - [6, 48], - [6, 49], - [6, 50], - [6, 51], - [6, 52], - [6, 53], - [6, 54], - [6, 55], - [6, 56], - [6, 57], - [6, 58], - [6, 59], - [6, 60], - [6, 61], - [6, 62], - [6, 63], - [6, 64], - [6, 65], - [6, 66], - [6, 67], - [6, 68], - [6, 69], - [6, 70], - [6, 71], - [6, 72], - [6, 73], - [6, 74], - [6, 75], - [6, 76], - [6, 77], - [6, 78], - [6, 79], - [6, 80], - [6, 81], - [6, 82], - [6, 83], - [6, 84], - [6, 85], - [6, 86], - [6, 87], - [6, 88], - [6, 89], - [6, 90], - [6, 91], - [6, 92], - [6, 93], - [6, 94], - [6, 95], - [6, 96], - [6, 97], - [6, 98], - [6, 99], - [6, 100], - [6, 101], - [6, 102], - [6, 103], - [6, 104], - [6, 105], - [6, 106], - [6, 107], - [6, 108], - [6, 109], - [6, 110], - [6, 111], - [6, 112], - [6, 113], - [6, 114], - [6, 115], - [6, 116], - [6, 117], - [6, 118], - [6, 119], - [6, 120], - [6, 121], - [6, 122], - [6, 123], - [6, 124], - [6, 125], - [6, 126], - [6, 127], - [6, 128], - [6, 129], - [6, 130], - [6, 131], - [6, 132], - [6, 133], - [6, 134], - [6, 135], - [6, 136], - [6, 137], - [6, 138], - [6, 139], - [6, 140], - [6, 141], - [6, 142], - [6, 143], - [6, 144], - [6, 145], - [6, 146], - [6, 147], - [6, 148], - [6, 149], - [6, 150], - [6, 151], - [6, 152], - [6, 153], - [6, 154], - [6, 155], - [6, 156], - [6, 157], - [6, 158], - [6, 159], - [6, 160], - [6, 161], - [6, 162], - [6, 163], - [6, 164], - [6, 165], - [6, 166], - [6, 167], - [6, 168], - [6, 169], - [6, 170], - [6, 171], - [6, 172], - [6, 173], - [6, 174], - [6, 175], - [6, 176], - [6, 177], - [6, 178], - [6, 179], - [6, 180], - [6, 181], - [6, 182], - [6, 183], - [6, 184], - [6, 185], - [6, 186], - [6, 187], - [6, 188], - [6, 189], - [6, 190], - [6, 191], - [6, 192], - [6, 193], - [6, 194], - [6, 195], - [6, 196], - [6, 197], - [6, 198], - [6, 199], - [6, 200], - [6, 201], - [6, 202], - [6, 203], - [6, 204], - [6, 205], - [6, 206], - [6, 207], - [6, 208], - [6, 209], - [6, 210], - [6, 211], - [6, 212], - [6, 213], - [6, 214], - [6, 215], - [6, 216], - [6, 217], - [6, 218], - [6, 219], - [6, 220], - [6, 221], - [6, 222], - [6, 223], - [6, 224], - [6, 225], - [6, 226], - [6, 227], - [6, 228], - [6, 229], - [6, 230], - [6, 231], - [6, 232], - [6, 233], - [6, 234], - [6, 235], - [6, 236], - [6, 237], - [6, 238], - [6, 239], - [6, 240], - [6, 241], - [6, 242], - [6, 243], - [6, 244], - [6, 245], - [6, 246], - [6, 247], - [6, 248], - [6, 249], - [6, 250], - [6, 251], - [6, 252], - [6, 253], - [6, 254], - [6, 255], - [6, 256], - [6, 257], - [6, 258], - [6, 259], - [6, 260], - [6, 261], - [6, 262], - [6, 263], - [6, 264], - [6, 265], - [6, 266], - [6, 267], - [6, 268], - [6, 269], - [6, 270], - [6, 271], - [6, 272], - [6, 273], - [6, 274], - [6, 275], - [6, 276], - [6, 277], - [6, 278], - [6, 279], - [6, 280], - [6, 281], - [6, 282], - [6, 283], - [6, 284], - [6, 285], - [6, 286], - [6, 287], - [6, 288], - [6, 289], - [6, 290], - [6, 291], - [6, 292], - [6, 293], - [6, 294], - [6, 295], - [6, 296], - [6, 297], - [6, 298], - [6, 299], - [6, 300], - [6, 301], - [6, 302], - [6, 303], - [6, 304], - [6, 305], - [6, 306], - [6, 307], - [6, 308], - [6, 309], - [6, 310], - [6, 311], - [6, 312], - [6, 313], - [6, 314], - [6, 315], - [6, 316], - [6, 317], - [6, 318], - [6, 319], - [6, 320], - [6, 321], - [6, 322], - [6, 323], - [6, 324], - [6, 325], - [6, 326], - [6, 327], - [6, 328], - [6, 329], - [6, 330], - [6, 331], - [6, 332], - [6, 333], - [6, 334], - [6, 335], - [6, 336], - [6, 337], - [6, 338], - [6, 339], - [6, 340], - [6, 341], - [6, 342], - [6, 343], - [6, 344], - [6, 345], - [6, 346], - [6, 347], - [6, 348], - [6, 349], - [6, 350], - [6, 351], - [6, 352], - [6, 353], - [6, 354], - [6, 355], - [6, 356], - [6, 357], - [6, 358], - [6, 359], - [6, 360], - [6, 361], - [6, 362], - [6, 363], - [6, 364], - [6, 365], - [6, 366], - [6, 367], - [6, 368], - [6, 369], - [6, 370], - [6, 371], - [6, 372], - [6, 373], - [6, 374], - [6, 375], - [6, 376], - [6, 377], - [6, 378], - [6, 379], - [6, 380], - [6, 381], - [6, 382], - [6, 383], - [6, 384], - [6, 385], - [6, 386], - [6, 387], - [6, 388], - [6, 389], - [6, 390], - [6, 391], - [6, 392], - [6, 393], - [6, 394], - [6, 395], - [6, 396], - [6, 397], - [6, 398], - [6, 399], - [6, 400], - [6, 401], - [6, 402], - [6, 403], - [6, 404], - [6, 405], - [6, 406], - [6, 407], - [6, 408], - [6, 409], - [6, 410], - [6, 411], - [6, 412], - [6, 413], - [6, 414], - [6, 415], - [6, 416], - [6, 417], - [6, 418], - [6, 419], - [6, 420], - [6, 421], - [6, 422], - [6, 423], - [6, 424], - [6, 425], - [6, 426], - [6, 427], - [6, 428], - [6, 429], - [6, 430], - [6, 431], - [6, 432], - [6, 433], - [6, 434], - [6, 435], - [6, 436], - [6, 437], - [6, 438], - [6, 439], - [6, 440], - [6, 441], - [6, 442], - [6, 443], - [6, 444], - [6, 445], - [6, 446], - [6, 447], - [6, 448], - [6, 449], - [6, 450], - [6, 451], - [6, 452], - [6, 453], - [6, 454], - [6, 455], - [6, 456], - [6, 457], - [6, 458], - [6, 459], - [6, 460], - [6, 461], - [6, 462], - [6, 463], - [6, 464], - [6, 465], - [6, 466], - [6, 467], - [6, 468], - [6, 469], - [6, 470], - [6, 471], - [6, 472], - [6, 473], - [6, 474], - [6, 475], - [6, 476], - [6, 477], - [6, 478], - [6, 479], - [6, 480], - [6, 481], - [6, 482], - [6, 483], - [6, 484], - [6, 485], - [6, 486], - [6, 487], - [6, 488], - [6, 489], - [6, 490], - [6, 491], - [6, 492], - [6, 493], - [6, 494], - [6, 495], - [6, 496], - [6, 497], - [6, 498], - [6, 499], - [6, 500], - [7, 2], - [7, 3], - [7, 4], - [7, 5], - [7, 6], - [7, 7], - [7, 8], - [7, 9], - [7, 10], - [7, 11], - [7, 12], - [7, 13], - [7, 14], - [7, 15], - [7, 16], - [7, 17], - [7, 18], - [7, 19], - [7, 20], - [7, 21], - [7, 22], - [7, 23], - [7, 24], - [7, 25], - [7, 26], - [7, 27], - [7, 28], - [7, 29], - [7, 30], - [7, 31], - [7, 32], - [7, 33], - [7, 34], - [7, 35], - [7, 36], - [7, 37], - [7, 38], - [7, 39], - [7, 40], - [7, 41], - [7, 42], - [7, 43], - [7, 44], - [7, 45], - [7, 46], - [7, 47], - [7, 48], - [7, 49], - [7, 50], - [7, 51], - [7, 52], - [7, 53], - [7, 54], - [7, 55], - [7, 56], - [7, 57], - [7, 58], - [7, 59], - [7, 60], - [7, 61], - [7, 62], - [7, 63], - [7, 64], - [7, 65], - [7, 66], - [7, 67], - [7, 68], - [7, 69], - [7, 70], - [7, 71], - [7, 72], - [7, 73], - [7, 74], - [7, 75], - [7, 76], - [7, 77], - [7, 78], - [7, 79], - [7, 80], - [7, 81], - [7, 82], - [7, 83], - [7, 84], - [7, 85], - [7, 86], - [7, 87], - [7, 88], - [7, 89], - [7, 90], - [7, 91], - [7, 92], - [7, 93], - [7, 94], - [7, 95], - [7, 96], - [7, 97], - [7, 98], - [7, 99], - [7, 100], - [7, 101], - [7, 102], - [7, 103], - [7, 104], - [7, 105], - [7, 106], - [7, 107], - [7, 108], - [7, 109], - [7, 110], - [7, 111], - [7, 112], - [7, 113], - [7, 114], - [7, 115], - [7, 116], - [7, 117], - [7, 118], - [7, 119], - [7, 120], - [7, 121], - [7, 122], - [7, 123], - [7, 124], - [7, 125], - [7, 126], - [7, 127], - [7, 128], - [7, 129], - [7, 130], - [7, 131], - [7, 132], - [7, 133], - [7, 134], - [7, 135], - [7, 136], - [7, 137], - [7, 138], - [7, 139], - [7, 140], - [7, 141], - [7, 142], - [7, 143], - [7, 144], - [7, 145], - [7, 146], - [7, 147], - [7, 148], - [7, 149], - [7, 150], - [7, 151], - [7, 152], - [7, 153], - [7, 154], - [7, 155], - [7, 156], - [7, 157], - [7, 158], - [7, 159], - [7, 160], - [7, 161], - [7, 162], - [7, 163], - [7, 164], - [7, 165], - [7, 166], - [7, 167], - [7, 168], - [7, 169], - [7, 170], - [7, 171], - [7, 172], - [7, 173], - [7, 174], - [7, 175], - [7, 176], - [7, 177], - [7, 178], - [7, 179], - [7, 180], - [7, 181], - [7, 182], - [7, 183], - [7, 184], - [7, 185], - [7, 186], - [7, 187], - [7, 188], - [7, 189], - [7, 190], - [7, 191], - [7, 192], - [7, 193], - [7, 194], - [7, 195], - [7, 196], - [7, 197], - [7, 198], - [7, 199], - [7, 200], - [7, 201], - [7, 202], - [7, 203], - [7, 204], - [7, 205], - [7, 206], - [7, 207], - [7, 208], - [7, 209], - [7, 210], - [7, 211], - [7, 212], - [7, 213], - [7, 214], - [7, 215], - [7, 216], - [7, 217], - [7, 218], - [7, 219], - [7, 220], - [7, 221], - [7, 222], - [7, 223], - [7, 224], - [7, 225], - [7, 226], - [7, 227], - [7, 228], - [7, 229], - [7, 230], - [7, 231], - [7, 232], - [7, 233], - [7, 234], - [7, 235], - [7, 236], - [7, 237], - [7, 238], - [7, 239], - [7, 240], - [7, 241], - [7, 242], - [7, 243], - [7, 244], - [7, 245], - [7, 246], - [7, 247], - [7, 248], - [7, 249], - [7, 250], - [7, 251], - [7, 252], - [7, 253], - [7, 254], - [7, 255], - [7, 256], - [7, 257], - [7, 258], - [7, 259], - [7, 260], - [7, 261], - [7, 262], - [7, 263], - [7, 264], - [7, 265], - [7, 266], - [7, 267], - [7, 268], - [7, 269], - [7, 270], - [7, 271], - [7, 272], - [7, 273], - [7, 274], - [7, 275], - [7, 276], - [7, 277], - [7, 278], - [7, 279], - [7, 280], - [7, 281], - [7, 282], - [7, 283], - [7, 284], - [7, 285], - [7, 286], - [7, 287], - [7, 288], - [7, 289], - [7, 290], - [7, 291], - [7, 292], - [7, 293], - [7, 294], - [7, 295], - [7, 296], - [7, 297], - [7, 298], - [7, 299], - [7, 300], - [7, 301], - [7, 302], - [7, 303], - [7, 304], - [7, 305], - [7, 306], - [7, 307], - [7, 308], - [7, 309], - [7, 310], - [7, 311], - [7, 312], - [7, 313], - [7, 314], - [7, 315], - [7, 316], - [7, 317], - [7, 318], - [7, 319], - [7, 320], - [7, 321], - [7, 322], - [7, 323], - [7, 324], - [7, 325], - [7, 326], - [7, 327], - [7, 328], - [7, 329], - [7, 330], - [7, 331], - [7, 332], - [7, 333], - [7, 334], - [7, 335], - [7, 336], - [7, 337], - [7, 338], - [7, 339], - [7, 340], - [7, 341], - [7, 342], - [7, 343], - [7, 344], - [7, 345], - [7, 346], - [7, 347], - [7, 348], - [7, 349], - [7, 350], - [7, 351], - [7, 352], - [7, 353], - [7, 354], - [7, 355], - [7, 356], - [7, 357], - [7, 358], - [7, 359], - [7, 360], - [7, 361], - [7, 362], - [7, 363], - [7, 364], - [7, 365], - [7, 366], - [7, 367], - [7, 368], - [7, 369], - [7, 370], - [7, 371], - [7, 372], - [7, 373], - [7, 374], - [7, 375], - [7, 376], - [7, 377], - [7, 378], - [7, 379], - [7, 380], - [7, 381], - [7, 382], - [7, 383], - [7, 384], - [7, 385], - [7, 386], - [7, 387], - [7, 388], - [7, 389], - [7, 390], - [7, 391], - [7, 392], - [7, 393], - [7, 394], - [7, 395], - [7, 396], - [7, 397], - [7, 398], - [7, 399], - [7, 400], - [7, 401], - [7, 402], - [7, 403], - [7, 404], - [7, 405], - [7, 406], - [7, 407], - [7, 408], - [7, 409], - [7, 410], - [7, 411], - [7, 412], - [7, 413], - [7, 414], - [7, 415], - [7, 416], - [7, 417], - [7, 418], - [7, 419], - [7, 420], - [7, 421], - [7, 422], - [7, 423], - [7, 424], - [7, 425], - [7, 426], - [7, 427], - [7, 428], - [7, 429], - [7, 430], - [7, 431], - [7, 432], - [7, 433], - [7, 434], - [7, 435], - [7, 436], - [7, 437], - [7, 438], - [7, 439], - [7, 440], - [7, 441], - [7, 442], - [7, 443], - [7, 444], - [7, 445], - [7, 446], - [7, 447], - [7, 448], - [7, 449], - [7, 450], - [7, 451], - [7, 452], - [7, 453], - [7, 454], - [7, 455], - [7, 456], - [7, 457], - [7, 458], - [7, 459], - [7, 460], - [7, 461], - [7, 462], - [7, 463], - [7, 464], - [7, 465], - [7, 466], - [7, 467], - [7, 468], - [7, 469], - [7, 470], - [7, 471], - [7, 472], - [7, 473], - [7, 474], - [7, 475], - [7, 476], - [7, 477], - [7, 478], - [7, 479], - [7, 480], - [7, 481], - [7, 482], - [7, 483], - [7, 484], - [7, 485], - [7, 486], - [7, 487], - [7, 488], - [7, 489], - [7, 490], - [7, 491], - [7, 492], - [7, 493], - [7, 494], - [7, 495], - [7, 496], - [7, 497], - [7, 498], - [7, 499], - [7, 500], - [8, 2], - [8, 3], - [8, 4], - [8, 5], - [8, 6], - [8, 7], - [8, 8], - [8, 9], - [8, 10], - [8, 11], - [8, 12], - [8, 13], - [8, 14], - [8, 15], - [8, 16], - [8, 17], - [8, 18], - [8, 19], - [8, 20], - [8, 21], - [8, 22], - [8, 23], - [8, 24], - [8, 25], - [8, 26], - [8, 27], - [8, 28], - [8, 29], - [8, 30], - [8, 31], - [8, 32], - [8, 33], - [8, 34], - [8, 35], - [8, 36], - [8, 37], - [8, 38], - [8, 39], - [8, 40], - [8, 41], - [8, 42], - [8, 43], - [8, 44], - [8, 45], - [8, 46], - [8, 47], - [8, 48], - [8, 49], - [8, 50], - [8, 51], - [8, 52], - [8, 53], - [8, 54], - [8, 55], - [8, 56], - [8, 57], - [8, 58], - [8, 59], - [8, 60], - [8, 61], - [8, 62], - [8, 63], - [8, 64], - [8, 65], - [8, 66], - [8, 67], - [8, 68], - [8, 69], - [8, 70], - [8, 71], - [8, 72], - [8, 73], - [8, 74], - [8, 75], - [8, 76], - [8, 77], - [8, 78], - [8, 79], - [8, 80], - [8, 81], - [8, 82], - [8, 83], - [8, 84], - [8, 85], - [8, 86], - [8, 87], - [8, 88], - [8, 89], - [8, 90], - [8, 91], - [8, 92], - [8, 93], - [8, 94], - [8, 95], - [8, 96], - [8, 97], - [8, 98], - [8, 99], - [8, 100], - [8, 101], - [8, 102], - [8, 103], - [8, 104], - [8, 105], - [8, 106], - [8, 107], - [8, 108], - [8, 109], - [8, 110], - [8, 111], - [8, 112], - [8, 113], - [8, 114], - [8, 115], - [8, 116], - [8, 117], - [8, 118], - [8, 119], - [8, 120], - [8, 121], - [8, 122], - [8, 123], - [8, 124], - [8, 125], - [8, 126], - [8, 127], - [8, 128], - [8, 129], - [8, 130], - [8, 131], - [8, 132], - [8, 133], - [8, 134], - [8, 135], - [8, 136], - [8, 137], - [8, 138], - [8, 139], - [8, 140], - [8, 141], - [8, 142], - [8, 143], - [8, 144], - [8, 145], - [8, 146], - [8, 147], - [8, 148], - [8, 149], - [8, 150], - [8, 151], - [8, 152], - [8, 153], - [8, 154], - [8, 155], - [8, 156], - [8, 157], - [8, 158], - [8, 159], - [8, 160], - [8, 161], - [8, 162], - [8, 163], - [8, 164], - [8, 165], - [8, 166], - [8, 167], - [8, 168], - [8, 169], - [8, 170], - [8, 171], - [8, 172], - [8, 173], - [8, 174], - [8, 175], - [8, 176], - [8, 177], - [8, 178], - [8, 179], - [8, 180], - [8, 181], - [8, 182], - [8, 183], - [8, 184], - [8, 185], - [8, 186], - [8, 187], - [8, 188], - [8, 189], - [8, 190], - [8, 191], - [8, 192], - [8, 193], - [8, 194], - [8, 195], - [8, 196], - [8, 197], - [8, 198], - [8, 199], - [8, 200], - [8, 201], - [8, 202], - [8, 203], - [8, 204], - [8, 205], - [8, 206], - [8, 207], - [8, 208], - [8, 209], - [8, 210], - [8, 211], - [8, 212], - [8, 213], - [8, 214], - [8, 215], - [8, 216], - [8, 217], - [8, 218], - [8, 219], - [8, 220], - [8, 221], - [8, 222], - [8, 223], - [8, 224], - [8, 225], - [8, 226], - [8, 227], - [8, 228], - [8, 229], - [8, 230], - [8, 231], - [8, 232], - [8, 233], - [8, 234], - [8, 235], - [8, 236], - [8, 237], - [8, 238], - [8, 239], - [8, 240], - [8, 241], - [8, 242], - [8, 243], - [8, 244], - [8, 245], - [8, 246], - [8, 247], - [8, 248], - [8, 249], - [8, 250], - [8, 251], - [8, 252], - [8, 253], - [8, 254], - [8, 255], - [8, 256], - [8, 257], - [8, 258], - [8, 259], - [8, 260], - [8, 261], - [8, 262], - [8, 263], - [8, 264], - [8, 265], - [8, 266], - [8, 267], - [8, 268], - [8, 269], - [8, 270], - [8, 271], - [8, 272], - [8, 273], - [8, 274], - [8, 275], - [8, 276], - [8, 277], - [8, 278], - [8, 279], - [8, 280], - [8, 281], - [8, 282], - [8, 283], - [8, 284], - [8, 285], - [8, 286], - [8, 287], - [8, 288], - [8, 289], - [8, 290], - [8, 291], - [8, 292], - [8, 293], - [8, 294], - [8, 295], - [8, 296], - [8, 297], - [8, 298], - [8, 299], - [8, 300], - [8, 301], - [8, 302], - [8, 303], - [8, 304], - [8, 305], - [8, 306], - [8, 307], - [8, 308], - [8, 309], - [8, 310], - [8, 311], - [8, 312], - [8, 313], - [8, 314], - [8, 315], - [8, 316], - [8, 317], - [8, 318], - [8, 319], - [8, 320], - [8, 321], - [8, 322], - [8, 323], - [8, 324], - [8, 325], - [8, 326], - [8, 327], - [8, 328], - [8, 329], - [8, 330], - [8, 331], - [8, 332], - [8, 333], - [8, 334], - [8, 335], - [8, 336], - [8, 337], - [8, 338], - [8, 339], - [8, 340], - [8, 341], - [8, 342], - [8, 343], - [8, 344], - [8, 345], - [8, 346], - [8, 347], - [8, 348], - [8, 349], - [8, 350], - [8, 351], - [8, 352], - [8, 353], - [8, 354], - [8, 355], - [8, 356], - [8, 357], - [8, 358], - [8, 359], - [8, 360], - [8, 361], - [8, 362], - [8, 363], - [8, 364], - [8, 365], - [8, 366], - [8, 367], - [8, 368], - [8, 369], - [8, 370], - [8, 371], - [8, 372], - [8, 373], - [8, 374], - [8, 375], - [8, 376], - [8, 377], - [8, 378], - [8, 379], - [8, 380], - [8, 381], - [8, 382], - [8, 383], - [8, 384], - [8, 385], - [8, 386], - [8, 387], - [8, 388], - [8, 389], - [8, 390], - [8, 391], - [8, 392], - [8, 393], - [8, 394], - [8, 395], - [8, 396], - [8, 397], - [8, 398], - [8, 399], - [8, 400], - [8, 401], - [8, 402], - [8, 403], - [8, 404], - [8, 405], - [8, 406], - [8, 407], - [8, 408], - [8, 409], - [8, 410], - [8, 411], - [8, 412], - [8, 413], - [8, 414], - [8, 415], - [8, 416], - [8, 417], - [8, 418], - [8, 419], - [8, 420], - [8, 421], - [8, 422], - [8, 423], - [8, 424], - [8, 425], - [8, 426], - [8, 427], - [8, 428], - [8, 429], - [8, 430], - [8, 431], - [8, 432], - [8, 433], - [8, 434], - [8, 435], - [8, 436], - [8, 437], - [8, 438], - [8, 439], - [8, 440], - [8, 441], - [8, 442], - [8, 443], - [8, 444], - [8, 445], - [8, 446], - [8, 447], - [8, 448], - [8, 449], - [8, 450], - [8, 451], - [8, 452], - [8, 453], - [8, 454], - [8, 455], - [8, 456], - [8, 457], - [8, 458], - [8, 459], - [8, 460], - [8, 461], - [8, 462], - [8, 463], - [8, 464], - [8, 465], - [8, 466], - [8, 467], - [8, 468], - [8, 469], - [8, 470], - [8, 471], - [8, 472], - [8, 473], - [8, 474], - [8, 475], - [8, 476], - [8, 477], - [8, 478], - [8, 479], - [8, 480], - [8, 481], - [8, 482], - [8, 483], - [8, 484], - [8, 485], - [8, 486], - [8, 487], - [8, 488], - [8, 489], - [8, 490], - [8, 491], - [8, 492], - [8, 493], - [8, 494], - [8, 495], - [8, 496], - [8, 497], - [8, 498], - [8, 499], - [8, 500] - ] - }, - { - "x": 13, - "y": 10, - "type": "COMPUTED", - "value": "iata", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 10, - "type": "COMPUTED", - "value": "name", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 10, - "type": "COMPUTED", - "value": "city", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 10, - "type": "COMPUTED", - "value": "state", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 10, - "type": "COMPUTED", - "value": "country", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 10, - "type": "COMPUTED", - "value": "latitude", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 10, - "type": "COMPUTED", - "value": "longitude", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 11, - "type": "COMPUTED", - "value": "3", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 11, - "type": "COMPUTED", - "value": "01G", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 11, - "type": "COMPUTED", - "value": "Perry-Warsaw", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 11, - "type": "COMPUTED", - "value": "Perry", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 11, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 11, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 11, - "type": "COMPUTED", - "value": "42.74134667", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 11, - "type": "COMPUTED", - "value": "-78.05208056", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 12, - "type": "COMPUTED", - "value": "19", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 12, - "type": "COMPUTED", - "value": "06N", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 12, - "type": "COMPUTED", - "value": "Randall", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 12, - "type": "COMPUTED", - "value": "Middletown", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 12, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 12, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 12, - "type": "COMPUTED", - "value": "41.43156583", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 12, - "type": "COMPUTED", - "value": "-74.39191722", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 13, - "type": "COMPUTED", - "value": "42", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 13, - "type": "COMPUTED", - "value": "0B8", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 13, - "type": "COMPUTED", - "value": "Elizabeth", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 13, - "type": "COMPUTED", - "value": "Fishers Island", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 13, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 13, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 13, - "type": "COMPUTED", - "value": "41.25130806", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 13, - "type": "COMPUTED", - "value": "-72.03161139", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 14, - "type": "COMPUTED", - "value": "54", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 14, - "type": "COMPUTED", - "value": "0G0", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 14, - "type": "COMPUTED", - "value": "North Buffalo Suburban", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 14, - "type": "COMPUTED", - "value": "Lockport", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 14, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 14, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 14, - "type": "COMPUTED", - "value": "43.10318389", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 14, - "type": "COMPUTED", - "value": "-78.70334583", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 15, - "type": "COMPUTED", - "value": "57", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 15, - "type": "COMPUTED", - "value": "0G7", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 15, - "type": "COMPUTED", - "value": "Finger Lakes Regional", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 15, - "type": "COMPUTED", - "value": "Seneca Falls", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 15, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 15, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 15, - "type": "COMPUTED", - "value": "42.88062278", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 15, - "type": "COMPUTED", - "value": "-76.78162028", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 16, - "type": "COMPUTED", - "value": "94", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 16, - "type": "COMPUTED", - "value": "10N", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 16, - "type": "COMPUTED", - "value": "Wallkill", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 16, - "type": "COMPUTED", - "value": "Wallkill", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 16, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 16, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 16, - "type": "COMPUTED", - "value": "41.62787111", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 16, - "type": "COMPUTED", - "value": "-74.13375583", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 11, - "y": 10, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-16T23:53:41.474Z" - }, - { - "x": 0, - "y": 104, - "type": "TEXT", - "value": "101", - "last_modified": "2023-02-17T00:02:05.652Z" - }, - { - "x": 1, - "y": 104, - "type": "TEXT", - "value": "12C", - "last_modified": "2023-02-17T00:02:05.654Z" - }, - { - "x": 2, - "y": 104, - "type": "TEXT", - "value": "Rochelle Municipal", - "last_modified": "2023-02-17T00:02:05.655Z" - }, - { - "x": 3, - "y": 104, - "type": "TEXT", - "value": "Rochelle", - "last_modified": "2023-02-17T00:02:05.657Z" - }, - { - "x": 4, - "y": 104, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:05.658Z" - }, - { - "x": 5, - "y": 104, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.660Z" - }, - { - "x": 6, - "y": 104, - "type": "TEXT", - "value": "41.89300139", - "last_modified": "2023-02-17T00:02:05.661Z" - }, - { - "x": 7, - "y": 104, - "type": "TEXT", - "value": "-89.07829", - "last_modified": "2023-02-17T00:02:05.663Z" - }, - { - "x": 0, - "y": 105, - "type": "TEXT", - "value": "102", - "last_modified": "2023-02-17T00:02:05.664Z" - }, - { - "x": 1, - "y": 105, - "type": "TEXT", - "value": "12D", - "last_modified": "2023-02-17T00:02:05.666Z" - }, - { - "x": 2, - "y": 105, - "type": "TEXT", - "value": "Tower Municipal", - "last_modified": "2023-02-17T00:02:05.667Z" - }, - { - "x": 3, - "y": 105, - "type": "TEXT", - "value": "Tower", - "last_modified": "2023-02-17T00:02:05.668Z" - }, - { - "x": 4, - "y": 105, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:05.670Z" - }, - { - "x": 5, - "y": 105, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.671Z" - }, - { - "x": 6, - "y": 105, - "type": "TEXT", - "value": "47.81833333", - "last_modified": "2023-02-17T00:02:05.673Z" - }, - { - "x": 7, - "y": 105, - "type": "TEXT", - "value": "-92.29166667", - "last_modified": "2023-02-17T00:02:05.674Z" - }, - { - "x": 0, - "y": 106, - "type": "TEXT", - "value": "103", - "last_modified": "2023-02-17T00:02:05.676Z" - }, - { - "x": 1, - "y": 106, - "type": "TEXT", - "value": "12J", - "last_modified": "2023-02-17T00:02:05.677Z" - }, - { - "x": 2, - "y": 106, - "type": "TEXT", - "value": "Brewton Municipal", - "last_modified": "2023-02-17T00:02:05.679Z" - }, - { - "x": 3, - "y": 106, - "type": "TEXT", - "value": "Brewton", - "last_modified": "2023-02-17T00:02:05.680Z" - }, - { - "x": 4, - "y": 106, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:05.682Z" - }, - { - "x": 5, - "y": 106, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.683Z" - }, - { - "x": 6, - "y": 106, - "type": "TEXT", - "value": "31.05126306", - "last_modified": "2023-02-17T00:02:05.684Z" - }, - { - "x": 7, - "y": 106, - "type": "TEXT", - "value": "-87.06796833", - "last_modified": "2023-02-17T00:02:05.686Z" - }, - { - "x": 0, - "y": 107, - "type": "TEXT", - "value": "104", - "last_modified": "2023-02-17T00:02:05.687Z" - }, - { - "x": 1, - "y": 107, - "type": "TEXT", - "value": "12K", - "last_modified": "2023-02-17T00:02:05.689Z" - }, - { - "x": 2, - "y": 107, - "type": "TEXT", - "value": "Superior Municipal", - "last_modified": "2023-02-17T00:02:05.690Z" - }, - { - "x": 3, - "y": 107, - "type": "TEXT", - "value": "Superior", - "last_modified": "2023-02-17T00:02:05.692Z" - }, - { - "x": 4, - "y": 107, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:05.693Z" - }, - { - "x": 5, - "y": 107, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.695Z" - }, - { - "x": 6, - "y": 107, - "type": "TEXT", - "value": "40.04636111", - "last_modified": "2023-02-17T00:02:05.696Z" - }, - { - "x": 7, - "y": 107, - "type": "TEXT", - "value": "-98.06011111", - "last_modified": "2023-02-17T00:02:05.697Z" - }, - { - "x": 0, - "y": 108, - "type": "TEXT", - "value": "105", - "last_modified": "2023-02-17T00:02:05.699Z" - }, - { - "x": 1, - "y": 108, - "type": "TEXT", - "value": "12Y", - "last_modified": "2023-02-17T00:02:05.700Z" - }, - { - "x": 2, - "y": 108, - "type": "TEXT", - "value": "Le Sueur Municipal", - "last_modified": "2023-02-17T00:02:05.702Z" - }, - { - "x": 3, - "y": 108, - "type": "TEXT", - "value": "Le Sueur", - "last_modified": "2023-02-17T00:02:05.703Z" - }, - { - "x": 4, - "y": 108, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:05.705Z" - }, - { - "x": 5, - "y": 108, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.706Z" - }, - { - "x": 6, - "y": 108, - "type": "TEXT", - "value": "44.43746472", - "last_modified": "2023-02-17T00:02:05.707Z" - }, - { - "x": 7, - "y": 108, - "type": "TEXT", - "value": "-93.91274083", - "last_modified": "2023-02-17T00:02:05.709Z" - }, - { - "x": 0, - "y": 109, - "type": "TEXT", - "value": "106", - "last_modified": "2023-02-17T00:02:05.710Z" - }, - { - "x": 1, - "y": 109, - "type": "TEXT", - "value": "13C", - "last_modified": "2023-02-17T00:02:05.712Z" - }, - { - "x": 2, - "y": 109, - "type": "TEXT", - "value": "Lakeview", - "last_modified": "2023-02-17T00:02:05.713Z" - }, - { - "x": 3, - "y": 109, - "type": "TEXT", - "value": "Lakeview", - "last_modified": "2023-02-17T00:02:05.714Z" - }, - { - "x": 4, - "y": 109, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:05.716Z" - }, - { - "x": 5, - "y": 109, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.717Z" - }, - { - "x": 6, - "y": 109, - "type": "TEXT", - "value": "43.45213722", - "last_modified": "2023-02-17T00:02:05.718Z" - }, - { - "x": 7, - "y": 109, - "type": "TEXT", - "value": "-85.26480333", - "last_modified": "2023-02-17T00:02:05.720Z" - }, - { - "x": 0, - "y": 110, - "type": "TEXT", - "value": "107", - "last_modified": "2023-02-17T00:02:05.721Z" - }, - { - "x": 1, - "y": 110, - "type": "TEXT", - "value": "13K", - "last_modified": "2023-02-17T00:02:05.723Z" - }, - { - "x": 2, - "y": 110, - "type": "TEXT", - "value": "Eureka Municipal", - "last_modified": "2023-02-17T00:02:05.724Z" - }, - { - "x": 3, - "y": 110, - "type": "TEXT", - "value": "Eureka", - "last_modified": "2023-02-17T00:02:05.725Z" - }, - { - "x": 4, - "y": 110, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:05.727Z" - }, - { - "x": 5, - "y": 110, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.728Z" - }, - { - "x": 6, - "y": 110, - "type": "TEXT", - "value": "37.8515825", - "last_modified": "2023-02-17T00:02:05.729Z" - }, - { - "x": 7, - "y": 110, - "type": "TEXT", - "value": "-96.29169806", - "last_modified": "2023-02-17T00:02:05.731Z" - }, - { - "x": 0, - "y": 111, - "type": "TEXT", - "value": "108", - "last_modified": "2023-02-17T00:02:05.732Z" - }, - { - "x": 1, - "y": 111, - "type": "TEXT", - "value": "13N", - "last_modified": "2023-02-17T00:02:05.734Z" - }, - { - "x": 2, - "y": 111, - "type": "TEXT", - "value": "Trinca", - "last_modified": "2023-02-17T00:02:05.735Z" - }, - { - "x": 3, - "y": 111, - "type": "TEXT", - "value": "Andover", - "last_modified": "2023-02-17T00:02:05.736Z" - }, - { - "x": 4, - "y": 111, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:05.738Z" - }, - { - "x": 5, - "y": 111, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.739Z" - }, - { - "x": 6, - "y": 111, - "type": "TEXT", - "value": "40.96676444", - "last_modified": "2023-02-17T00:02:05.740Z" - }, - { - "x": 7, - "y": 111, - "type": "TEXT", - "value": "-74.78016556", - "last_modified": "2023-02-17T00:02:05.742Z" - }, - { - "x": 0, - "y": 112, - "type": "TEXT", - "value": "109", - "last_modified": "2023-02-17T00:02:05.743Z" - }, - { - "x": 1, - "y": 112, - "type": "TEXT", - "value": "14J", - "last_modified": "2023-02-17T00:02:05.744Z" - }, - { - "x": 2, - "y": 112, - "type": "TEXT", - "value": "Carl Folsom", - "last_modified": "2023-02-17T00:02:05.746Z" - }, - { - "x": 3, - "y": 112, - "type": "TEXT", - "value": "Elba", - "last_modified": "2023-02-17T00:02:05.747Z" - }, - { - "x": 4, - "y": 112, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:05.748Z" - }, - { - "x": 5, - "y": 112, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.750Z" - }, - { - "x": 6, - "y": 112, - "type": "TEXT", - "value": "31.40988861", - "last_modified": "2023-02-17T00:02:05.751Z" - }, - { - "x": 7, - "y": 112, - "type": "TEXT", - "value": "-86.08883583", - "last_modified": "2023-02-17T00:02:05.752Z" - }, - { - "x": 0, - "y": 113, - "type": "TEXT", - "value": "110", - "last_modified": "2023-02-17T00:02:05.754Z" - }, - { - "x": 1, - "y": 113, - "type": "TEXT", - "value": "14M", - "last_modified": "2023-02-17T00:02:05.755Z" - }, - { - "x": 2, - "y": 113, - "type": "TEXT", - "value": "Hollandale Municipal", - "last_modified": "2023-02-17T00:02:05.756Z" - }, - { - "x": 3, - "y": 113, - "type": "TEXT", - "value": "Hollandale", - "last_modified": "2023-02-17T00:02:05.758Z" - }, - { - "x": 4, - "y": 113, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:05.759Z" - }, - { - "x": 5, - "y": 113, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.760Z" - }, - { - "x": 6, - "y": 113, - "type": "TEXT", - "value": "33.18262167", - "last_modified": "2023-02-17T00:02:05.762Z" - }, - { - "x": 7, - "y": 113, - "type": "TEXT", - "value": "-90.83065444", - "last_modified": "2023-02-17T00:02:05.763Z" - }, - { - "x": 0, - "y": 114, - "type": "TEXT", - "value": "111", - "last_modified": "2023-02-17T00:02:05.764Z" - }, - { - "x": 1, - "y": 114, - "type": "TEXT", - "value": "14Y", - "last_modified": "2023-02-17T00:02:05.765Z" - }, - { - "x": 2, - "y": 114, - "type": "TEXT", - "value": "Todd Field", - "last_modified": "2023-02-17T00:02:05.767Z" - }, - { - "x": 3, - "y": 114, - "type": "TEXT", - "value": "Long Prairie", - "last_modified": "2023-02-17T00:02:05.768Z" - }, - { - "x": 4, - "y": 114, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:05.769Z" - }, - { - "x": 5, - "y": 114, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.771Z" - }, - { - "x": 6, - "y": 114, - "type": "TEXT", - "value": "45.89857556", - "last_modified": "2023-02-17T00:02:05.772Z" - }, - { - "x": 7, - "y": 114, - "type": "TEXT", - "value": "-94.87391", - "last_modified": "2023-02-17T00:02:05.773Z" - }, - { - "x": 0, - "y": 115, - "type": "TEXT", - "value": "112", - "last_modified": "2023-02-17T00:02:05.775Z" - }, - { - "x": 1, - "y": 115, - "type": "TEXT", - "value": "15F", - "last_modified": "2023-02-17T00:02:05.776Z" - }, - { - "x": 2, - "y": 115, - "type": "TEXT", - "value": "Haskell Municipal", - "last_modified": "2023-02-17T00:02:05.777Z" - }, - { - "x": 3, - "y": 115, - "type": "TEXT", - "value": "Haskell", - "last_modified": "2023-02-17T00:02:05.778Z" - }, - { - "x": 4, - "y": 115, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:05.780Z" - }, - { - "x": 5, - "y": 115, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.781Z" - }, - { - "x": 6, - "y": 115, - "type": "TEXT", - "value": "33.19155556", - "last_modified": "2023-02-17T00:02:05.782Z" - }, - { - "x": 7, - "y": 115, - "type": "TEXT", - "value": "-99.71793056", - "last_modified": "2023-02-17T00:02:05.784Z" - }, - { - "x": 0, - "y": 116, - "type": "TEXT", - "value": "113", - "last_modified": "2023-02-17T00:02:05.785Z" - }, - { - "x": 1, - "y": 116, - "type": "TEXT", - "value": "15J", - "last_modified": "2023-02-17T00:02:05.786Z" - }, - { - "x": 2, - "y": 116, - "type": "TEXT", - "value": "Cook County", - "last_modified": "2023-02-17T00:02:05.787Z" - }, - { - "x": 3, - "y": 116, - "type": "TEXT", - "value": "Adel", - "last_modified": "2023-02-17T00:02:05.789Z" - }, - { - "x": 4, - "y": 116, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:05.790Z" - }, - { - "x": 5, - "y": 116, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.791Z" - }, - { - "x": 6, - "y": 116, - "type": "TEXT", - "value": "31.13780556", - "last_modified": "2023-02-17T00:02:05.792Z" - }, - { - "x": 7, - "y": 116, - "type": "TEXT", - "value": "-83.45308333", - "last_modified": "2023-02-17T00:02:05.794Z" - }, - { - "x": 0, - "y": 117, - "type": "TEXT", - "value": "114", - "last_modified": "2023-02-17T00:02:05.795Z" - }, - { - "x": 1, - "y": 117, - "type": "TEXT", - "value": "15M", - "last_modified": "2023-02-17T00:02:05.796Z" - }, - { - "x": 2, - "y": 117, - "type": "TEXT", - "value": "Luka", - "last_modified": "2023-02-17T00:02:05.797Z" - }, - { - "x": 3, - "y": 117, - "type": "TEXT", - "value": "Luka", - "last_modified": "2023-02-17T00:02:05.799Z" - }, - { - "x": 4, - "y": 117, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:05.800Z" - }, - { - "x": 5, - "y": 117, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.801Z" - }, - { - "x": 6, - "y": 117, - "type": "TEXT", - "value": "34.7723125", - "last_modified": "2023-02-17T00:02:05.802Z" - }, - { - "x": 7, - "y": 117, - "type": "TEXT", - "value": "-88.16587444", - "last_modified": "2023-02-17T00:02:05.804Z" - }, - { - "x": 0, - "y": 118, - "type": "TEXT", - "value": "115", - "last_modified": "2023-02-17T00:02:05.805Z" - }, - { - "x": 1, - "y": 118, - "type": "TEXT", - "value": "15Z", - "last_modified": "2023-02-17T00:02:05.806Z" - }, - { - "x": 2, - "y": 118, - "type": "TEXT", - "value": "McCarthy 2", - "last_modified": "2023-02-17T00:02:05.807Z" - }, - { - "x": 3, - "y": 118, - "type": "TEXT", - "value": "McCarthy", - "last_modified": "2023-02-17T00:02:05.809Z" - }, - { - "x": 4, - "y": 118, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:05.810Z" - }, - { - "x": 5, - "y": 118, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.811Z" - }, - { - "x": 6, - "y": 118, - "type": "TEXT", - "value": "61.43706083", - "last_modified": "2023-02-17T00:02:05.812Z" - }, - { - "x": 7, - "y": 118, - "type": "TEXT", - "value": "-142.9037372", - "last_modified": "2023-02-17T00:02:05.814Z" - }, - { - "x": 0, - "y": 119, - "type": "TEXT", - "value": "116", - "last_modified": "2023-02-17T00:02:05.815Z" - }, - { - "x": 1, - "y": 119, - "type": "TEXT", - "value": "16A", - "last_modified": "2023-02-17T00:02:05.816Z" - }, - { - "x": 2, - "y": 119, - "type": "TEXT", - "value": "Nunapitchuk", - "last_modified": "2023-02-17T00:02:05.817Z" - }, - { - "x": 3, - "y": 119, - "type": "TEXT", - "value": "Nunapitchuk", - "last_modified": "2023-02-17T00:02:05.818Z" - }, - { - "x": 4, - "y": 119, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:05.820Z" - }, - { - "x": 5, - "y": 119, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.821Z" - }, - { - "x": 6, - "y": 119, - "type": "TEXT", - "value": "60.90582833", - "last_modified": "2023-02-17T00:02:05.822Z" - }, - { - "x": 7, - "y": 119, - "type": "TEXT", - "value": "-162.4391158", - "last_modified": "2023-02-17T00:02:05.823Z" - }, - { - "x": 0, - "y": 120, - "type": "TEXT", - "value": "117", - "last_modified": "2023-02-17T00:02:05.824Z" - }, - { - "x": 1, - "y": 120, - "type": "TEXT", - "value": "16G", - "last_modified": "2023-02-17T00:02:05.826Z" - }, - { - "x": 2, - "y": 120, - "type": "TEXT", - "value": "Seneca County", - "last_modified": "2023-02-17T00:02:05.827Z" - }, - { - "x": 3, - "y": 120, - "type": "TEXT", - "value": "Tiffin", - "last_modified": "2023-02-17T00:02:05.828Z" - }, - { - "x": 4, - "y": 120, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:05.829Z" - }, - { - "x": 5, - "y": 120, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.830Z" - }, - { - "x": 6, - "y": 120, - "type": "TEXT", - "value": "41.09405556", - "last_modified": "2023-02-17T00:02:05.832Z" - }, - { - "x": 7, - "y": 120, - "type": "TEXT", - "value": "-83.2125", - "last_modified": "2023-02-17T00:02:05.833Z" - }, - { - "x": 0, - "y": 121, - "type": "TEXT", - "value": "118", - "last_modified": "2023-02-17T00:02:05.834Z" - }, - { - "x": 1, - "y": 121, - "type": "TEXT", - "value": "16J", - "last_modified": "2023-02-17T00:02:05.835Z" - }, - { - "x": 2, - "y": 121, - "type": "TEXT", - "value": "Dawson Municipal", - "last_modified": "2023-02-17T00:02:05.836Z" - }, - { - "x": 3, - "y": 121, - "type": "TEXT", - "value": "Dawson", - "last_modified": "2023-02-17T00:02:05.838Z" - }, - { - "x": 4, - "y": 121, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:05.839Z" - }, - { - "x": 5, - "y": 121, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.840Z" - }, - { - "x": 6, - "y": 121, - "type": "TEXT", - "value": "31.74328472", - "last_modified": "2023-02-17T00:02:05.841Z" - }, - { - "x": 7, - "y": 121, - "type": "TEXT", - "value": "-84.419285", - "last_modified": "2023-02-17T00:02:05.842Z" - }, - { - "x": 0, - "y": 122, - "type": "TEXT", - "value": "119", - "last_modified": "2023-02-17T00:02:05.843Z" - }, - { - "x": 1, - "y": 122, - "type": "TEXT", - "value": "16S", - "last_modified": "2023-02-17T00:02:05.845Z" - }, - { - "x": 2, - "y": 122, - "type": "TEXT", - "value": "Myrtle Creek Municipal", - "last_modified": "2023-02-17T00:02:05.846Z" - }, - { - "x": 3, - "y": 122, - "type": "TEXT", - "value": "Myrtle Creek", - "last_modified": "2023-02-17T00:02:05.847Z" - }, - { - "x": 4, - "y": 122, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:05.848Z" - }, - { - "x": 5, - "y": 122, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.849Z" - }, - { - "x": 6, - "y": 122, - "type": "TEXT", - "value": "42.99845056", - "last_modified": "2023-02-17T00:02:05.850Z" - }, - { - "x": 7, - "y": 122, - "type": "TEXT", - "value": "-123.3095092", - "last_modified": "2023-02-17T00:02:05.852Z" - }, - { - "x": 0, - "y": 123, - "type": "TEXT", - "value": "120", - "last_modified": "2023-02-17T00:02:05.853Z" - }, - { - "x": 1, - "y": 123, - "type": "TEXT", - "value": "17G", - "last_modified": "2023-02-17T00:02:05.854Z" - }, - { - "x": 2, - "y": 123, - "type": "TEXT", - "value": "Port Bucyrus-Crawford County", - "last_modified": "2023-02-17T00:02:05.855Z" - }, - { - "x": 3, - "y": 123, - "type": "TEXT", - "value": "Bucyrus", - "last_modified": "2023-02-17T00:02:05.856Z" - }, - { - "x": 4, - "y": 123, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:05.858Z" - }, - { - "x": 5, - "y": 123, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.859Z" - }, - { - "x": 6, - "y": 123, - "type": "TEXT", - "value": "40.78141667", - "last_modified": "2023-02-17T00:02:05.860Z" - }, - { - "x": 7, - "y": 123, - "type": "TEXT", - "value": "-82.97469444", - "last_modified": "2023-02-17T00:02:05.861Z" - }, - { - "x": 0, - "y": 124, - "type": "TEXT", - "value": "121", - "last_modified": "2023-02-17T00:02:05.862Z" - }, - { - "x": 1, - "y": 124, - "type": "TEXT", - "value": "17J", - "last_modified": "2023-02-17T00:02:05.863Z" - }, - { - "x": 2, - "y": 124, - "type": "TEXT", - "value": "Donalsonville Municipal", - "last_modified": "2023-02-17T00:02:05.864Z" - }, - { - "x": 3, - "y": 124, - "type": "TEXT", - "value": "Donalsonville", - "last_modified": "2023-02-17T00:02:05.866Z" - }, - { - "x": 4, - "y": 124, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:05.867Z" - }, - { - "x": 5, - "y": 124, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.868Z" - }, - { - "x": 6, - "y": 124, - "type": "TEXT", - "value": "31.00694444", - "last_modified": "2023-02-17T00:02:05.869Z" - }, - { - "x": 7, - "y": 124, - "type": "TEXT", - "value": "-84.87761111", - "last_modified": "2023-02-17T00:02:05.870Z" - }, - { - "x": 0, - "y": 125, - "type": "TEXT", - "value": "122", - "last_modified": "2023-02-17T00:02:05.871Z" - }, - { - "x": 1, - "y": 125, - "type": "TEXT", - "value": "17K", - "last_modified": "2023-02-17T00:02:05.872Z" - }, - { - "x": 2, - "y": 125, - "type": "TEXT", - "value": "Boise City", - "last_modified": "2023-02-17T00:02:05.873Z" - }, - { - "x": 3, - "y": 125, - "type": "TEXT", - "value": "Boise City", - "last_modified": "2023-02-17T00:02:05.875Z" - }, - { - "x": 4, - "y": 125, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:05.876Z" - }, - { - "x": 5, - "y": 125, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.877Z" - }, - { - "x": 6, - "y": 125, - "type": "TEXT", - "value": "36.77430028", - "last_modified": "2023-02-17T00:02:05.878Z" - }, - { - "x": 7, - "y": 125, - "type": "TEXT", - "value": "-102.5104364", - "last_modified": "2023-02-17T00:02:05.879Z" - }, - { - "x": 0, - "y": 126, - "type": "TEXT", - "value": "123", - "last_modified": "2023-02-17T00:02:05.880Z" - }, - { - "x": 1, - "y": 126, - "type": "TEXT", - "value": "17M", - "last_modified": "2023-02-17T00:02:05.881Z" - }, - { - "x": 2, - "y": 126, - "type": "TEXT", - "value": "Magee Municipal", - "last_modified": "2023-02-17T00:02:05.882Z" - }, - { - "x": 3, - "y": 126, - "type": "TEXT", - "value": "Magee", - "last_modified": "2023-02-17T00:02:05.883Z" - }, - { - "x": 4, - "y": 126, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:05.885Z" - }, - { - "x": 5, - "y": 126, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.886Z" - }, - { - "x": 6, - "y": 126, - "type": "TEXT", - "value": "31.86127139", - "last_modified": "2023-02-17T00:02:05.887Z" - }, - { - "x": 7, - "y": 126, - "type": "TEXT", - "value": "-89.80285361", - "last_modified": "2023-02-17T00:02:05.888Z" - }, - { - "x": 0, - "y": 127, - "type": "TEXT", - "value": "124", - "last_modified": "2023-02-17T00:02:05.889Z" - }, - { - "x": 1, - "y": 127, - "type": "TEXT", - "value": "17N", - "last_modified": "2023-02-17T00:02:05.890Z" - }, - { - "x": 2, - "y": 127, - "type": "TEXT", - "value": "Cross Keys", - "last_modified": "2023-02-17T00:02:05.891Z" - }, - { - "x": 3, - "y": 127, - "type": "TEXT", - "value": "Cross Keys", - "last_modified": "2023-02-17T00:02:05.892Z" - }, - { - "x": 4, - "y": 127, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:05.893Z" - }, - { - "x": 5, - "y": 127, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.894Z" - }, - { - "x": 6, - "y": 127, - "type": "TEXT", - "value": "39.70547583", - "last_modified": "2023-02-17T00:02:05.895Z" - }, - { - "x": 7, - "y": 127, - "type": "TEXT", - "value": "-75.03300306", - "last_modified": "2023-02-17T00:02:05.896Z" - }, - { - "x": 0, - "y": 128, - "type": "TEXT", - "value": "125", - "last_modified": "2023-02-17T00:02:05.898Z" - }, - { - "x": 1, - "y": 128, - "type": "TEXT", - "value": "17Z", - "last_modified": "2023-02-17T00:02:05.899Z" - }, - { - "x": 2, - "y": 128, - "type": "TEXT", - "value": "Manokotak", - "last_modified": "2023-02-17T00:02:05.900Z" - }, - { - "x": 3, - "y": 128, - "type": "TEXT", - "value": "Manokotak", - "last_modified": "2023-02-17T00:02:05.901Z" - }, - { - "x": 4, - "y": 128, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:05.902Z" - }, - { - "x": 5, - "y": 128, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.903Z" - }, - { - "x": 6, - "y": 128, - "type": "TEXT", - "value": "58.98896583", - "last_modified": "2023-02-17T00:02:05.904Z" - }, - { - "x": 7, - "y": 128, - "type": "TEXT", - "value": "-159.0499739", - "last_modified": "2023-02-17T00:02:05.905Z" - }, - { - "x": 0, - "y": 129, - "type": "TEXT", - "value": "126", - "last_modified": "2023-02-17T00:02:05.906Z" - }, - { - "x": 1, - "y": 129, - "type": "TEXT", - "value": "18A", - "last_modified": "2023-02-17T00:02:05.907Z" - }, - { - "x": 2, - "y": 129, - "type": "TEXT", - "value": "Franklin County", - "last_modified": "2023-02-17T00:02:05.908Z" - }, - { - "x": 3, - "y": 129, - "type": "TEXT", - "value": "Canon", - "last_modified": "2023-02-17T00:02:05.909Z" - }, - { - "x": 4, - "y": 129, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:05.910Z" - }, - { - "x": 5, - "y": 129, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.911Z" - }, - { - "x": 6, - "y": 129, - "type": "TEXT", - "value": "34.34010472", - "last_modified": "2023-02-17T00:02:05.912Z" - }, - { - "x": 7, - "y": 129, - "type": "TEXT", - "value": "-83.13348333", - "last_modified": "2023-02-17T00:02:05.913Z" - }, - { - "x": 0, - "y": 130, - "type": "TEXT", - "value": "127", - "last_modified": "2023-02-17T00:02:05.914Z" - }, - { - "x": 1, - "y": 130, - "type": "TEXT", - "value": "18I", - "last_modified": "2023-02-17T00:02:05.915Z" - }, - { - "x": 2, - "y": 130, - "type": "TEXT", - "value": "McCreary County", - "last_modified": "2023-02-17T00:02:05.917Z" - }, - { - "x": 3, - "y": 130, - "type": "TEXT", - "value": "Pine Knot", - "last_modified": "2023-02-17T00:02:05.918Z" - }, - { - "x": 4, - "y": 130, - "type": "TEXT", - "value": "KY", - "last_modified": "2023-02-17T00:02:05.919Z" - }, - { - "x": 5, - "y": 130, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.920Z" - }, - { - "x": 6, - "y": 130, - "type": "TEXT", - "value": "36.69591306", - "last_modified": "2023-02-17T00:02:05.921Z" - }, - { - "x": 7, - "y": 130, - "type": "TEXT", - "value": "-84.39160389", - "last_modified": "2023-02-17T00:02:05.922Z" - }, - { - "x": 0, - "y": 131, - "type": "TEXT", - "value": "128", - "last_modified": "2023-02-17T00:02:05.923Z" - }, - { - "x": 1, - "y": 131, - "type": "TEXT", - "value": "19A", - "last_modified": "2023-02-17T00:02:05.924Z" - }, - { - "x": 2, - "y": 131, - "type": "TEXT", - "value": "Jackson County", - "last_modified": "2023-02-17T00:02:05.925Z" - }, - { - "x": 3, - "y": 131, - "type": "TEXT", - "value": "Jefferson", - "last_modified": "2023-02-17T00:02:05.926Z" - }, - { - "x": 4, - "y": 131, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:05.927Z" - }, - { - "x": 5, - "y": 131, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.928Z" - }, - { - "x": 6, - "y": 131, - "type": "TEXT", - "value": "34.17402472", - "last_modified": "2023-02-17T00:02:05.929Z" - }, - { - "x": 7, - "y": 131, - "type": "TEXT", - "value": "-83.56066528", - "last_modified": "2023-02-17T00:02:05.930Z" - }, - { - "x": 0, - "y": 132, - "type": "TEXT", - "value": "129", - "last_modified": "2023-02-17T00:02:05.931Z" - }, - { - "x": 1, - "y": 132, - "type": "TEXT", - "value": "19M", - "last_modified": "2023-02-17T00:02:05.932Z" - }, - { - "x": 2, - "y": 132, - "type": "TEXT", - "value": "C A Moore", - "last_modified": "2023-02-17T00:02:05.933Z" - }, - { - "x": 3, - "y": 132, - "type": "TEXT", - "value": "Lexington", - "last_modified": "2023-02-17T00:02:05.934Z" - }, - { - "x": 4, - "y": 132, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:05.935Z" - }, - { - "x": 5, - "y": 132, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.936Z" - }, - { - "x": 6, - "y": 132, - "type": "TEXT", - "value": "33.12546111", - "last_modified": "2023-02-17T00:02:05.937Z" - }, - { - "x": 7, - "y": 132, - "type": "TEXT", - "value": "-90.02555694", - "last_modified": "2023-02-17T00:02:05.938Z" - }, - { - "x": 0, - "y": 133, - "type": "TEXT", - "value": "130", - "last_modified": "2023-02-17T00:02:05.939Z" - }, - { - "x": 1, - "y": 133, - "type": "TEXT", - "value": "19N", - "last_modified": "2023-02-17T00:02:05.940Z" - }, - { - "x": 2, - "y": 133, - "type": "TEXT", - "value": "Camden", - "last_modified": "2023-02-17T00:02:05.941Z" - }, - { - "x": 3, - "y": 133, - "type": "TEXT", - "value": "Berlin", - "last_modified": "2023-02-17T00:02:05.942Z" - }, - { - "x": 4, - "y": 133, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:05.943Z" - }, - { - "x": 5, - "y": 133, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.944Z" - }, - { - "x": 6, - "y": 133, - "type": "TEXT", - "value": "39.77842056", - "last_modified": "2023-02-17T00:02:05.945Z" - }, - { - "x": 7, - "y": 133, - "type": "TEXT", - "value": "-74.94780389", - "last_modified": "2023-02-17T00:02:05.946Z" - }, - { - "x": 0, - "y": 134, - "type": "TEXT", - "value": "131", - "last_modified": "2023-02-17T00:02:05.947Z" - }, - { - "x": 1, - "y": 134, - "type": "TEXT", - "value": "19P", - "last_modified": "2023-02-17T00:02:05.948Z" - }, - { - "x": 2, - "y": 134, - "type": "TEXT", - "value": "Port Protection SPB", - "last_modified": "2023-02-17T00:02:05.949Z" - }, - { - "x": 3, - "y": 134, - "type": "TEXT", - "value": "Port Protection", - "last_modified": "2023-02-17T00:02:05.950Z" - }, - { - "x": 4, - "y": 134, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:05.951Z" - }, - { - "x": 5, - "y": 134, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.952Z" - }, - { - "x": 6, - "y": 134, - "type": "TEXT", - "value": "56.32880417", - "last_modified": "2023-02-17T00:02:05.953Z" - }, - { - "x": 7, - "y": 134, - "type": "TEXT", - "value": "-133.6100844", - "last_modified": "2023-02-17T00:02:05.954Z" - }, - { - "x": 0, - "y": 135, - "type": "TEXT", - "value": "132", - "last_modified": "2023-02-17T00:02:05.954Z" - }, - { - "x": 1, - "y": 135, - "type": "TEXT", - "value": "1A3", - "last_modified": "2023-02-17T00:02:05.955Z" - }, - { - "x": 2, - "y": 135, - "type": "TEXT", - "value": "Martin Campbell", - "last_modified": "2023-02-17T00:02:05.956Z" - }, - { - "x": 3, - "y": 135, - "type": "TEXT", - "value": "Copperhill", - "last_modified": "2023-02-17T00:02:05.957Z" - }, - { - "x": 4, - "y": 135, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:05.958Z" - }, - { - "x": 5, - "y": 135, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.959Z" - }, - { - "x": 6, - "y": 135, - "type": "TEXT", - "value": "35.01619111", - "last_modified": "2023-02-17T00:02:05.960Z" - }, - { - "x": 7, - "y": 135, - "type": "TEXT", - "value": "-84.34631083", - "last_modified": "2023-02-17T00:02:05.961Z" - }, - { - "x": 0, - "y": 136, - "type": "TEXT", - "value": "133", - "last_modified": "2023-02-17T00:02:05.962Z" - }, - { - "x": 1, - "y": 136, - "type": "TEXT", - "value": "1A5", - "last_modified": "2023-02-17T00:02:05.963Z" - }, - { - "x": 2, - "y": 136, - "type": "TEXT", - "value": "Macon County", - "last_modified": "2023-02-17T00:02:05.964Z" - }, - { - "x": 3, - "y": 136, - "type": "TEXT", - "value": "Franklin", - "last_modified": "2023-02-17T00:02:05.965Z" - }, - { - "x": 4, - "y": 136, - "type": "TEXT", - "value": "NC", - "last_modified": "2023-02-17T00:02:05.966Z" - }, - { - "x": 5, - "y": 136, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.967Z" - }, - { - "x": 6, - "y": 136, - "type": "TEXT", - "value": "35.222595", - "last_modified": "2023-02-17T00:02:05.968Z" - }, - { - "x": 7, - "y": 136, - "type": "TEXT", - "value": "-83.41904389", - "last_modified": "2023-02-17T00:02:05.969Z" - }, - { - "x": 0, - "y": 137, - "type": "TEXT", - "value": "134", - "last_modified": "2023-02-17T00:02:05.970Z" - }, - { - "x": 1, - "y": 137, - "type": "TEXT", - "value": "1A6", - "last_modified": "2023-02-17T00:02:05.971Z" - }, - { - "x": 2, - "y": 137, - "type": "TEXT", - "value": "Middlesboro-Bell County", - "last_modified": "2023-02-17T00:02:05.972Z" - }, - { - "x": 3, - "y": 137, - "type": "TEXT", - "value": "Middlesboro", - "last_modified": "2023-02-17T00:02:05.973Z" - }, - { - "x": 4, - "y": 137, - "type": "TEXT", - "value": "KY", - "last_modified": "2023-02-17T00:02:05.973Z" - }, - { - "x": 5, - "y": 137, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.974Z" - }, - { - "x": 6, - "y": 137, - "type": "TEXT", - "value": "36.6106375", - "last_modified": "2023-02-17T00:02:05.975Z" - }, - { - "x": 7, - "y": 137, - "type": "TEXT", - "value": "-83.73741611", - "last_modified": "2023-02-17T00:02:05.976Z" - }, - { - "x": 0, - "y": 138, - "type": "TEXT", - "value": "135", - "last_modified": "2023-02-17T00:02:05.977Z" - }, - { - "x": 1, - "y": 138, - "type": "TEXT", - "value": "1A7", - "last_modified": "2023-02-17T00:02:05.978Z" - }, - { - "x": 2, - "y": 138, - "type": "TEXT", - "value": "Jackson County", - "last_modified": "2023-02-17T00:02:05.979Z" - }, - { - "x": 3, - "y": 138, - "type": "TEXT", - "value": "Gainesboro", - "last_modified": "2023-02-17T00:02:05.980Z" - }, - { - "x": 4, - "y": 138, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:05.981Z" - }, - { - "x": 5, - "y": 138, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.982Z" - }, - { - "x": 6, - "y": 138, - "type": "TEXT", - "value": "36.39728139", - "last_modified": "2023-02-17T00:02:05.983Z" - }, - { - "x": 7, - "y": 138, - "type": "TEXT", - "value": "-85.64164278", - "last_modified": "2023-02-17T00:02:05.984Z" - }, - { - "x": 0, - "y": 139, - "type": "TEXT", - "value": "136", - "last_modified": "2023-02-17T00:02:05.984Z" - }, - { - "x": 1, - "y": 139, - "type": "TEXT", - "value": "1A9", - "last_modified": "2023-02-17T00:02:05.985Z" - }, - { - "x": 2, - "y": 139, - "type": "TEXT", - "value": "Autauga County", - "last_modified": "2023-02-17T00:02:05.986Z" - }, - { - "x": 3, - "y": 139, - "type": "TEXT", - "value": "Prattville", - "last_modified": "2023-02-17T00:02:05.987Z" - }, - { - "x": 4, - "y": 139, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:05.988Z" - }, - { - "x": 5, - "y": 139, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.989Z" - }, - { - "x": 6, - "y": 139, - "type": "TEXT", - "value": "32.438775", - "last_modified": "2023-02-17T00:02:05.990Z" - }, - { - "x": 7, - "y": 139, - "type": "TEXT", - "value": "-86.51044778", - "last_modified": "2023-02-17T00:02:05.991Z" - }, - { - "x": 0, - "y": 140, - "type": "TEXT", - "value": "137", - "last_modified": "2023-02-17T00:02:05.992Z" - }, - { - "x": 1, - "y": 140, - "type": "TEXT", - "value": "1B0", - "last_modified": "2023-02-17T00:02:05.993Z" - }, - { - "x": 2, - "y": 140, - "type": "TEXT", - "value": "Dexter Regional", - "last_modified": "2023-02-17T00:02:05.994Z" - }, - { - "x": 3, - "y": 140, - "type": "TEXT", - "value": "Dexter", - "last_modified": "2023-02-17T00:02:05.994Z" - }, - { - "x": 4, - "y": 140, - "type": "TEXT", - "value": "ME", - "last_modified": "2023-02-17T00:02:05.995Z" - }, - { - "x": 5, - "y": 140, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:05.996Z" - }, - { - "x": 6, - "y": 140, - "type": "TEXT", - "value": "45.00839444", - "last_modified": "2023-02-17T00:02:05.997Z" - }, - { - "x": 7, - "y": 140, - "type": "TEXT", - "value": "-69.23976722", - "last_modified": "2023-02-17T00:02:05.998Z" - }, - { - "x": 0, - "y": 141, - "type": "TEXT", - "value": "138", - "last_modified": "2023-02-17T00:02:05.999Z" - }, - { - "x": 1, - "y": 141, - "type": "TEXT", - "value": "1B1", - "last_modified": "2023-02-17T00:02:06.000Z" - }, - { - "x": 2, - "y": 141, - "type": "TEXT", - "value": "Columbia Cty", - "last_modified": "2023-02-17T00:02:06.001Z" - }, - { - "x": 3, - "y": 141, - "type": "TEXT", - "value": "Hudson", - "last_modified": "2023-02-17T00:02:06.002Z" - }, - { - "x": 4, - "y": 141, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:06.002Z" - }, - { - "x": 5, - "y": 141, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.003Z" - }, - { - "x": 6, - "y": 141, - "type": "TEXT", - "value": "42.29130028", - "last_modified": "2023-02-17T00:02:06.004Z" - }, - { - "x": 7, - "y": 141, - "type": "TEXT", - "value": "-73.71031944", - "last_modified": "2023-02-17T00:02:06.005Z" - }, - { - "x": 0, - "y": 142, - "type": "TEXT", - "value": "139", - "last_modified": "2023-02-17T00:02:06.006Z" - }, - { - "x": 1, - "y": 142, - "type": "TEXT", - "value": "1B3", - "last_modified": "2023-02-17T00:02:06.007Z" - }, - { - "x": 2, - "y": 142, - "type": "TEXT", - "value": "Fair Haven", - "last_modified": "2023-02-17T00:02:06.008Z" - }, - { - "x": 3, - "y": 142, - "type": "TEXT", - "value": "Fair Haven", - "last_modified": "2023-02-17T00:02:06.008Z" - }, - { - "x": 4, - "y": 142, - "type": "TEXT", - "value": "VT", - "last_modified": "2023-02-17T00:02:06.009Z" - }, - { - "x": 5, - "y": 142, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.010Z" - }, - { - "x": 6, - "y": 142, - "type": "TEXT", - "value": "43.61534389", - "last_modified": "2023-02-17T00:02:06.011Z" - }, - { - "x": 7, - "y": 142, - "type": "TEXT", - "value": "-73.27455556", - "last_modified": "2023-02-17T00:02:06.012Z" - }, - { - "x": 0, - "y": 143, - "type": "TEXT", - "value": "140", - "last_modified": "2023-02-17T00:02:06.013Z" - }, - { - "x": 1, - "y": 143, - "type": "TEXT", - "value": "1B9", - "last_modified": "2023-02-17T00:02:06.014Z" - }, - { - "x": 2, - "y": 143, - "type": "TEXT", - "value": "Mansfield Municipal", - "last_modified": "2023-02-17T00:02:06.014Z" - }, - { - "x": 3, - "y": 143, - "type": "TEXT", - "value": "Mansfield", - "last_modified": "2023-02-17T00:02:06.015Z" - }, - { - "x": 4, - "y": 143, - "type": "TEXT", - "value": "MA", - "last_modified": "2023-02-17T00:02:06.016Z" - }, - { - "x": 5, - "y": 143, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.017Z" - }, - { - "x": 6, - "y": 143, - "type": "TEXT", - "value": "42.00013306", - "last_modified": "2023-02-17T00:02:06.018Z" - }, - { - "x": 7, - "y": 143, - "type": "TEXT", - "value": "-71.19677139", - "last_modified": "2023-02-17T00:02:06.019Z" - }, - { - "x": 0, - "y": 144, - "type": "TEXT", - "value": "141", - "last_modified": "2023-02-17T00:02:06.019Z" - }, - { - "x": 1, - "y": 144, - "type": "TEXT", - "value": "1C5", - "last_modified": "2023-02-17T00:02:06.020Z" - }, - { - "x": 2, - "y": 144, - "type": "TEXT", - "value": "Clow", - "last_modified": "2023-02-17T00:02:06.021Z" - }, - { - "x": 3, - "y": 144, - "type": "TEXT", - "value": "Chicago/Plainfield", - "last_modified": "2023-02-17T00:02:06.022Z" - }, - { - "x": 4, - "y": 144, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:06.023Z" - }, - { - "x": 5, - "y": 144, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.024Z" - }, - { - "x": 6, - "y": 144, - "type": "TEXT", - "value": "41.69597444", - "last_modified": "2023-02-17T00:02:06.024Z" - }, - { - "x": 7, - "y": 144, - "type": "TEXT", - "value": "-88.12923056", - "last_modified": "2023-02-17T00:02:06.025Z" - }, - { - "x": 0, - "y": 145, - "type": "TEXT", - "value": "142", - "last_modified": "2023-02-17T00:02:06.026Z" - }, - { - "x": 1, - "y": 145, - "type": "TEXT", - "value": "1D1", - "last_modified": "2023-02-17T00:02:06.027Z" - }, - { - "x": 2, - "y": 145, - "type": "TEXT", - "value": "Milbank Municipal", - "last_modified": "2023-02-17T00:02:06.028Z" - }, - { - "x": 3, - "y": 145, - "type": "TEXT", - "value": "Milbank", - "last_modified": "2023-02-17T00:02:06.029Z" - }, - { - "x": 4, - "y": 145, - "type": "TEXT", - "value": "SD", - "last_modified": "2023-02-17T00:02:06.029Z" - }, - { - "x": 5, - "y": 145, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.030Z" - }, - { - "x": 6, - "y": 145, - "type": "TEXT", - "value": "45.23053806", - "last_modified": "2023-02-17T00:02:06.031Z" - }, - { - "x": 7, - "y": 145, - "type": "TEXT", - "value": "-96.56596556", - "last_modified": "2023-02-17T00:02:06.032Z" - }, - { - "x": 0, - "y": 146, - "type": "TEXT", - "value": "143", - "last_modified": "2023-02-17T00:02:06.033Z" - }, - { - "x": 1, - "y": 146, - "type": "TEXT", - "value": "1D2", - "last_modified": "2023-02-17T00:02:06.033Z" - }, - { - "x": 2, - "y": 146, - "type": "TEXT", - "value": "Canton -Plymouth - Mettetal", - "last_modified": "2023-02-17T00:02:06.034Z" - }, - { - "x": 3, - "y": 146, - "type": "TEXT", - "value": "Plymouth", - "last_modified": "2023-02-17T00:02:06.035Z" - }, - { - "x": 4, - "y": 146, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:06.036Z" - }, - { - "x": 5, - "y": 146, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.037Z" - }, - { - "x": 6, - "y": 146, - "type": "TEXT", - "value": "42.35003667", - "last_modified": "2023-02-17T00:02:06.037Z" - }, - { - "x": 7, - "y": 146, - "type": "TEXT", - "value": "-83.45826833", - "last_modified": "2023-02-17T00:02:06.038Z" - }, - { - "x": 0, - "y": 147, - "type": "TEXT", - "value": "144", - "last_modified": "2023-02-17T00:02:06.039Z" - }, - { - "x": 1, - "y": 147, - "type": "TEXT", - "value": "1D3", - "last_modified": "2023-02-17T00:02:06.040Z" - }, - { - "x": 2, - "y": 147, - "type": "TEXT", - "value": "Platte Municipal", - "last_modified": "2023-02-17T00:02:06.041Z" - }, - { - "x": 3, - "y": 147, - "type": "TEXT", - "value": "Platte", - "last_modified": "2023-02-17T00:02:06.041Z" - }, - { - "x": 4, - "y": 147, - "type": "TEXT", - "value": "SD", - "last_modified": "2023-02-17T00:02:06.042Z" - }, - { - "x": 5, - "y": 147, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.043Z" - }, - { - "x": 6, - "y": 147, - "type": "TEXT", - "value": "43.40332833", - "last_modified": "2023-02-17T00:02:06.044Z" - }, - { - "x": 7, - "y": 147, - "type": "TEXT", - "value": "-98.82952972", - "last_modified": "2023-02-17T00:02:06.045Z" - }, - { - "x": 0, - "y": 148, - "type": "TEXT", - "value": "145", - "last_modified": "2023-02-17T00:02:06.045Z" - }, - { - "x": 1, - "y": 148, - "type": "TEXT", - "value": "1D6", - "last_modified": "2023-02-17T00:02:06.046Z" - }, - { - "x": 2, - "y": 148, - "type": "TEXT", - "value": "Hector Municipal", - "last_modified": "2023-02-17T00:02:06.047Z" - }, - { - "x": 3, - "y": 148, - "type": "TEXT", - "value": "Hector", - "last_modified": "2023-02-17T00:02:06.048Z" - }, - { - "x": 4, - "y": 148, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:06.049Z" - }, - { - "x": 5, - "y": 148, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.049Z" - }, - { - "x": 6, - "y": 148, - "type": "TEXT", - "value": "44.73107278", - "last_modified": "2023-02-17T00:02:06.050Z" - }, - { - "x": 7, - "y": 148, - "type": "TEXT", - "value": "-94.71471333", - "last_modified": "2023-02-17T00:02:06.051Z" - }, - { - "x": 0, - "y": 149, - "type": "TEXT", - "value": "146", - "last_modified": "2023-02-17T00:02:06.052Z" - }, - { - "x": 1, - "y": 149, - "type": "TEXT", - "value": "1D7", - "last_modified": "2023-02-17T00:02:06.052Z" - }, - { - "x": 2, - "y": 149, - "type": "TEXT", - "value": "Webster Municipal", - "last_modified": "2023-02-17T00:02:06.053Z" - }, - { - "x": 3, - "y": 149, - "type": "TEXT", - "value": "Webster", - "last_modified": "2023-02-17T00:02:06.054Z" - }, - { - "x": 4, - "y": 149, - "type": "TEXT", - "value": "SD", - "last_modified": "2023-02-17T00:02:06.055Z" - }, - { - "x": 5, - "y": 149, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.055Z" - }, - { - "x": 6, - "y": 149, - "type": "TEXT", - "value": "45.29329111", - "last_modified": "2023-02-17T00:02:06.056Z" - }, - { - "x": 7, - "y": 149, - "type": "TEXT", - "value": "-97.51369889", - "last_modified": "2023-02-17T00:02:06.057Z" - }, - { - "x": 0, - "y": 150, - "type": "TEXT", - "value": "147", - "last_modified": "2023-02-17T00:02:06.058Z" - }, - { - "x": 1, - "y": 150, - "type": "TEXT", - "value": "1D8", - "last_modified": "2023-02-17T00:02:06.059Z" - }, - { - "x": 2, - "y": 150, - "type": "TEXT", - "value": "Redfield Municipal", - "last_modified": "2023-02-17T00:02:06.059Z" - }, - { - "x": 3, - "y": 150, - "type": "TEXT", - "value": "Redfield", - "last_modified": "2023-02-17T00:02:06.060Z" - }, - { - "x": 4, - "y": 150, - "type": "TEXT", - "value": "SD", - "last_modified": "2023-02-17T00:02:06.061Z" - }, - { - "x": 5, - "y": 150, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.062Z" - }, - { - "x": 6, - "y": 150, - "type": "TEXT", - "value": "44.86247611", - "last_modified": "2023-02-17T00:02:06.062Z" - }, - { - "x": 7, - "y": 150, - "type": "TEXT", - "value": "-98.52953972", - "last_modified": "2023-02-17T00:02:06.063Z" - }, - { - "x": 0, - "y": 151, - "type": "TEXT", - "value": "148", - "last_modified": "2023-02-17T00:02:06.064Z" - }, - { - "x": 1, - "y": 151, - "type": "TEXT", - "value": "1F0", - "last_modified": "2023-02-17T00:02:06.065Z" - }, - { - "x": 2, - "y": 151, - "type": "TEXT", - "value": "Downtown Ardmore", - "last_modified": "2023-02-17T00:02:06.065Z" - }, - { - "x": 3, - "y": 151, - "type": "TEXT", - "value": "Ardmore", - "last_modified": "2023-02-17T00:02:06.066Z" - }, - { - "x": 4, - "y": 151, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:06.067Z" - }, - { - "x": 5, - "y": 151, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.067Z" - }, - { - "x": 6, - "y": 151, - "type": "TEXT", - "value": "34.14698917", - "last_modified": "2023-02-17T00:02:06.068Z" - }, - { - "x": 7, - "y": 151, - "type": "TEXT", - "value": "-97.12265194", - "last_modified": "2023-02-17T00:02:06.069Z" - }, - { - "x": 0, - "y": 152, - "type": "TEXT", - "value": "149", - "last_modified": "2023-02-17T00:02:06.070Z" - }, - { - "x": 1, - "y": 152, - "type": "TEXT", - "value": "1F1", - "last_modified": "2023-02-17T00:02:06.070Z" - }, - { - "x": 2, - "y": 152, - "type": "TEXT", - "value": "Lake Murray State Park", - "last_modified": "2023-02-17T00:02:06.071Z" - }, - { - "x": 3, - "y": 152, - "type": "TEXT", - "value": "Overbrook", - "last_modified": "2023-02-17T00:02:06.072Z" - }, - { - "x": 4, - "y": 152, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:06.073Z" - }, - { - "x": 5, - "y": 152, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.073Z" - }, - { - "x": 6, - "y": 152, - "type": "TEXT", - "value": "34.07509694", - "last_modified": "2023-02-17T00:02:06.074Z" - }, - { - "x": 7, - "y": 152, - "type": "TEXT", - "value": "-97.10667917", - "last_modified": "2023-02-17T00:02:06.075Z" - }, - { - "x": 0, - "y": 153, - "type": "TEXT", - "value": "150", - "last_modified": "2023-02-17T00:02:06.075Z" - }, - { - "x": 1, - "y": 153, - "type": "TEXT", - "value": "1F4", - "last_modified": "2023-02-17T00:02:06.076Z" - }, - { - "x": 2, - "y": 153, - "type": "TEXT", - "value": "Madill Municipal", - "last_modified": "2023-02-17T00:02:06.077Z" - }, - { - "x": 3, - "y": 153, - "type": "TEXT", - "value": "Madill", - "last_modified": "2023-02-17T00:02:06.078Z" - }, - { - "x": 4, - "y": 153, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:06.078Z" - }, - { - "x": 5, - "y": 153, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.079Z" - }, - { - "x": 6, - "y": 153, - "type": "TEXT", - "value": "34.14040194", - "last_modified": "2023-02-17T00:02:06.080Z" - }, - { - "x": 7, - "y": 153, - "type": "TEXT", - "value": "-96.81203222", - "last_modified": "2023-02-17T00:02:06.080Z" - }, - { - "x": 0, - "y": 154, - "type": "TEXT", - "value": "151", - "last_modified": "2023-02-17T00:02:06.081Z" - }, - { - "x": 1, - "y": 154, - "type": "TEXT", - "value": "1F9", - "last_modified": "2023-02-17T00:02:06.082Z" - }, - { - "x": 2, - "y": 154, - "type": "TEXT", - "value": "Bridgeport Municipal", - "last_modified": "2023-02-17T00:02:06.083Z" - }, - { - "x": 3, - "y": 154, - "type": "TEXT", - "value": "Bridgeport", - "last_modified": "2023-02-17T00:02:06.083Z" - }, - { - "x": 4, - "y": 154, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:06.084Z" - }, - { - "x": 5, - "y": 154, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.085Z" - }, - { - "x": 6, - "y": 154, - "type": "TEXT", - "value": "33.17533333", - "last_modified": "2023-02-17T00:02:06.085Z" - }, - { - "x": 7, - "y": 154, - "type": "TEXT", - "value": "-97.82838889", - "last_modified": "2023-02-17T00:02:06.086Z" - }, - { - "x": 0, - "y": 155, - "type": "TEXT", - "value": "152", - "last_modified": "2023-02-17T00:02:06.087Z" - }, - { - "x": 1, - "y": 155, - "type": "TEXT", - "value": "1G0", - "last_modified": "2023-02-17T00:02:06.087Z" - }, - { - "x": 2, - "y": 155, - "type": "TEXT", - "value": "Wood County", - "last_modified": "2023-02-17T00:02:06.088Z" - }, - { - "x": 3, - "y": 155, - "type": "TEXT", - "value": "Bowling Green", - "last_modified": "2023-02-17T00:02:06.089Z" - }, - { - "x": 4, - "y": 155, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:06.090Z" - }, - { - "x": 5, - "y": 155, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.090Z" - }, - { - "x": 6, - "y": 155, - "type": "TEXT", - "value": "41.391", - "last_modified": "2023-02-17T00:02:06.091Z" - }, - { - "x": 7, - "y": 155, - "type": "TEXT", - "value": "-83.63013889", - "last_modified": "2023-02-17T00:02:06.092Z" - }, - { - "x": 0, - "y": 156, - "type": "TEXT", - "value": "153", - "last_modified": "2023-02-17T00:02:06.092Z" - }, - { - "x": 1, - "y": 156, - "type": "TEXT", - "value": "1G3", - "last_modified": "2023-02-17T00:02:06.093Z" - }, - { - "x": 2, - "y": 156, - "type": "TEXT", - "value": "Kent State University", - "last_modified": "2023-02-17T00:02:06.094Z" - }, - { - "x": 3, - "y": 156, - "type": "TEXT", - "value": "Kent", - "last_modified": "2023-02-17T00:02:06.094Z" - }, - { - "x": 4, - "y": 156, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:06.095Z" - }, - { - "x": 5, - "y": 156, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.096Z" - }, - { - "x": 6, - "y": 156, - "type": "TEXT", - "value": "41.15186167", - "last_modified": "2023-02-17T00:02:06.096Z" - }, - { - "x": 7, - "y": 156, - "type": "TEXT", - "value": "-81.41658306", - "last_modified": "2023-02-17T00:02:06.097Z" - }, - { - "x": 0, - "y": 157, - "type": "TEXT", - "value": "154", - "last_modified": "2023-02-17T00:02:06.098Z" - }, - { - "x": 1, - "y": 157, - "type": "TEXT", - "value": "1G4", - "last_modified": "2023-02-17T00:02:06.098Z" - }, - { - "x": 2, - "y": 157, - "type": "TEXT", - "value": "Grand Canyon West", - "last_modified": "2023-02-17T00:02:06.099Z" - }, - { - "x": 3, - "y": 157, - "type": "TEXT", - "value": "Peach Springs", - "last_modified": "2023-02-17T00:02:06.100Z" - }, - { - "x": 4, - "y": 157, - "type": "TEXT", - "value": "AZ", - "last_modified": "2023-02-17T00:02:06.100Z" - }, - { - "x": 5, - "y": 157, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.101Z" - }, - { - "x": 6, - "y": 157, - "type": "TEXT", - "value": "35.99221", - "last_modified": "2023-02-17T00:02:06.102Z" - }, - { - "x": 7, - "y": 157, - "type": "TEXT", - "value": "-113.8166164", - "last_modified": "2023-02-17T00:02:06.102Z" - }, - { - "x": 0, - "y": 158, - "type": "TEXT", - "value": "155", - "last_modified": "2023-02-17T00:02:06.103Z" - }, - { - "x": 1, - "y": 158, - "type": "TEXT", - "value": "1G5", - "last_modified": "2023-02-17T00:02:06.104Z" - }, - { - "x": 2, - "y": 158, - "type": "TEXT", - "value": "Freedom", - "last_modified": "2023-02-17T00:02:06.104Z" - }, - { - "x": 3, - "y": 158, - "type": "TEXT", - "value": "Medina", - "last_modified": "2023-02-17T00:02:06.105Z" - }, - { - "x": 4, - "y": 158, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:06.106Z" - }, - { - "x": 5, - "y": 158, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.106Z" - }, - { - "x": 6, - "y": 158, - "type": "TEXT", - "value": "41.13144444", - "last_modified": "2023-02-17T00:02:06.107Z" - }, - { - "x": 7, - "y": 158, - "type": "TEXT", - "value": "-81.76491667", - "last_modified": "2023-02-17T00:02:06.108Z" - }, - { - "x": 0, - "y": 159, - "type": "TEXT", - "value": "156", - "last_modified": "2023-02-17T00:02:06.108Z" - }, - { - "x": 1, - "y": 159, - "type": "TEXT", - "value": "1G6", - "last_modified": "2023-02-17T00:02:06.109Z" - }, - { - "x": 2, - "y": 159, - "type": "TEXT", - "value": "Michael", - "last_modified": "2023-02-17T00:02:06.109Z" - }, - { - "x": 3, - "y": 159, - "type": "TEXT", - "value": "Cicero", - "last_modified": "2023-02-17T00:02:06.110Z" - }, - { - "x": 4, - "y": 159, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:06.111Z" - }, - { - "x": 5, - "y": 159, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.111Z" - }, - { - "x": 6, - "y": 159, - "type": "TEXT", - "value": "43.18166667", - "last_modified": "2023-02-17T00:02:06.112Z" - }, - { - "x": 7, - "y": 159, - "type": "TEXT", - "value": "-76.12777778", - "last_modified": "2023-02-17T00:02:06.113Z" - }, - { - "x": 0, - "y": 160, - "type": "TEXT", - "value": "157", - "last_modified": "2023-02-17T00:02:06.113Z" - }, - { - "x": 1, - "y": 160, - "type": "TEXT", - "value": "1H0", - "last_modified": "2023-02-17T00:02:06.114Z" - }, - { - "x": 2, - "y": 160, - "type": "TEXT", - "value": "Creve Coeur", - "last_modified": "2023-02-17T00:02:06.115Z" - }, - { - "x": 3, - "y": 160, - "type": "TEXT", - "value": "St Louis", - "last_modified": "2023-02-17T00:02:06.115Z" - }, - { - "x": 4, - "y": 160, - "type": "TEXT", - "value": "MO", - "last_modified": "2023-02-17T00:02:06.116Z" - }, - { - "x": 5, - "y": 160, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.116Z" - }, - { - "x": 6, - "y": 160, - "type": "TEXT", - "value": "38.72752", - "last_modified": "2023-02-17T00:02:06.117Z" - }, - { - "x": 7, - "y": 160, - "type": "TEXT", - "value": "-90.50830417", - "last_modified": "2023-02-17T00:02:06.118Z" - }, - { - "x": 0, - "y": 161, - "type": "TEXT", - "value": "158", - "last_modified": "2023-02-17T00:02:06.118Z" - }, - { - "x": 1, - "y": 161, - "type": "TEXT", - "value": "1H2", - "last_modified": "2023-02-17T00:02:06.119Z" - }, - { - "x": 2, - "y": 161, - "type": "TEXT", - "value": "Effingham County Memorial", - "last_modified": "2023-02-17T00:02:06.120Z" - }, - { - "x": 3, - "y": 161, - "type": "TEXT", - "value": "Effingham", - "last_modified": "2023-02-17T00:02:06.120Z" - }, - { - "x": 4, - "y": 161, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:06.121Z" - }, - { - "x": 5, - "y": 161, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.122Z" - }, - { - "x": 6, - "y": 161, - "type": "TEXT", - "value": "39.07045083", - "last_modified": "2023-02-17T00:02:06.122Z" - }, - { - "x": 7, - "y": 161, - "type": "TEXT", - "value": "-88.53351972", - "last_modified": "2023-02-17T00:02:06.123Z" - }, - { - "x": 0, - "y": 162, - "type": "TEXT", - "value": "159", - "last_modified": "2023-02-17T00:02:06.123Z" - }, - { - "x": 1, - "y": 162, - "type": "TEXT", - "value": "1H3", - "last_modified": "2023-02-17T00:02:06.124Z" - }, - { - "x": 2, - "y": 162, - "type": "TEXT", - "value": "Linn State Tech. College", - "last_modified": "2023-02-17T00:02:06.125Z" - }, - { - "x": 3, - "y": 162, - "type": "TEXT", - "value": "Linn", - "last_modified": "2023-02-17T00:02:06.125Z" - }, - { - "x": 4, - "y": 162, - "type": "TEXT", - "value": "MO", - "last_modified": "2023-02-17T00:02:06.126Z" - }, - { - "x": 5, - "y": 162, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.126Z" - }, - { - "x": 6, - "y": 162, - "type": "TEXT", - "value": "38.47149444", - "last_modified": "2023-02-17T00:02:06.127Z" - }, - { - "x": 7, - "y": 162, - "type": "TEXT", - "value": "-91.81531667", - "last_modified": "2023-02-17T00:02:06.128Z" - }, - { - "x": 0, - "y": 163, - "type": "TEXT", - "value": "160", - "last_modified": "2023-02-17T00:02:06.128Z" - }, - { - "x": 1, - "y": 163, - "type": "TEXT", - "value": "1H8", - "last_modified": "2023-02-17T00:02:06.129Z" - }, - { - "x": 2, - "y": 163, - "type": "TEXT", - "value": "Casey Municipal", - "last_modified": "2023-02-17T00:02:06.129Z" - }, - { - "x": 3, - "y": 163, - "type": "TEXT", - "value": "Casey", - "last_modified": "2023-02-17T00:02:06.130Z" - }, - { - "x": 4, - "y": 163, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:06.131Z" - }, - { - "x": 5, - "y": 163, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.131Z" - }, - { - "x": 6, - "y": 163, - "type": "TEXT", - "value": "39.30250917", - "last_modified": "2023-02-17T00:02:06.132Z" - }, - { - "x": 7, - "y": 163, - "type": "TEXT", - "value": "-88.00406194", - "last_modified": "2023-02-17T00:02:06.132Z" - }, - { - "x": 0, - "y": 164, - "type": "TEXT", - "value": "161", - "last_modified": "2023-02-17T00:02:06.133Z" - }, - { - "x": 1, - "y": 164, - "type": "TEXT", - "value": "1I5", - "last_modified": "2023-02-17T00:02:06.134Z" - }, - { - "x": 2, - "y": 164, - "type": "TEXT", - "value": "Freehold", - "last_modified": "2023-02-17T00:02:06.134Z" - }, - { - "x": 3, - "y": 164, - "type": "TEXT", - "value": "Freehold", - "last_modified": "2023-02-17T00:02:06.135Z" - }, - { - "x": 4, - "y": 164, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:06.135Z" - }, - { - "x": 5, - "y": 164, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.136Z" - }, - { - "x": 6, - "y": 164, - "type": "TEXT", - "value": "42.36425", - "last_modified": "2023-02-17T00:02:06.136Z" - }, - { - "x": 7, - "y": 164, - "type": "TEXT", - "value": "-74.06596806", - "last_modified": "2023-02-17T00:02:06.137Z" - }, - { - "x": 0, - "y": 165, - "type": "TEXT", - "value": "162", - "last_modified": "2023-02-17T00:02:06.138Z" - }, - { - "x": 1, - "y": 165, - "type": "TEXT", - "value": "1I9", - "last_modified": "2023-02-17T00:02:06.138Z" - }, - { - "x": 2, - "y": 165, - "type": "TEXT", - "value": "Delphi Municipal", - "last_modified": "2023-02-17T00:02:06.139Z" - }, - { - "x": 3, - "y": 165, - "type": "TEXT", - "value": "Delphi", - "last_modified": "2023-02-17T00:02:06.139Z" - }, - { - "x": 4, - "y": 165, - "type": "TEXT", - "value": "IN", - "last_modified": "2023-02-17T00:02:06.140Z" - }, - { - "x": 5, - "y": 165, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.140Z" - }, - { - "x": 6, - "y": 165, - "type": "TEXT", - "value": "40.54281417", - "last_modified": "2023-02-17T00:02:06.141Z" - }, - { - "x": 7, - "y": 165, - "type": "TEXT", - "value": "-86.68167194", - "last_modified": "2023-02-17T00:02:06.142Z" - }, - { - "x": 0, - "y": 166, - "type": "TEXT", - "value": "163", - "last_modified": "2023-02-17T00:02:06.142Z" - }, - { - "x": 1, - "y": 166, - "type": "TEXT", - "value": "1J0", - "last_modified": "2023-02-17T00:02:06.143Z" - }, - { - "x": 2, - "y": 166, - "type": "TEXT", - "value": "Tri-County", - "last_modified": "2023-02-17T00:02:06.143Z" - }, - { - "x": 3, - "y": 166, - "type": "TEXT", - "value": "Bonifay", - "last_modified": "2023-02-17T00:02:06.144Z" - }, - { - "x": 4, - "y": 166, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:06.144Z" - }, - { - "x": 5, - "y": 166, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.145Z" - }, - { - "x": 6, - "y": 166, - "type": "TEXT", - "value": "30.84577778", - "last_modified": "2023-02-17T00:02:06.146Z" - }, - { - "x": 7, - "y": 166, - "type": "TEXT", - "value": "-85.60138889", - "last_modified": "2023-02-17T00:02:06.146Z" - }, - { - "x": 0, - "y": 167, - "type": "TEXT", - "value": "164", - "last_modified": "2023-02-17T00:02:06.147Z" - }, - { - "x": 1, - "y": 167, - "type": "TEXT", - "value": "1K2", - "last_modified": "2023-02-17T00:02:06.147Z" - }, - { - "x": 2, - "y": 167, - "type": "TEXT", - "value": "Lindsay Municipal", - "last_modified": "2023-02-17T00:02:06.148Z" - }, - { - "x": 3, - "y": 167, - "type": "TEXT", - "value": "Lindsay", - "last_modified": "2023-02-17T00:02:06.148Z" - }, - { - "x": 4, - "y": 167, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:06.149Z" - }, - { - "x": 5, - "y": 167, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.149Z" - }, - { - "x": 6, - "y": 167, - "type": "TEXT", - "value": "34.85007333", - "last_modified": "2023-02-17T00:02:06.150Z" - }, - { - "x": 7, - "y": 167, - "type": "TEXT", - "value": "-97.58642028", - "last_modified": "2023-02-17T00:02:06.150Z" - }, - { - "x": 0, - "y": 168, - "type": "TEXT", - "value": "165", - "last_modified": "2023-02-17T00:02:06.151Z" - }, - { - "x": 1, - "y": 168, - "type": "TEXT", - "value": "1K4", - "last_modified": "2023-02-17T00:02:06.152Z" - }, - { - "x": 2, - "y": 168, - "type": "TEXT", - "value": "David J. Perry", - "last_modified": "2023-02-17T00:02:06.152Z" - }, - { - "x": 3, - "y": 168, - "type": "TEXT", - "value": "Goldsby", - "last_modified": "2023-02-17T00:02:06.153Z" - }, - { - "x": 4, - "y": 168, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:06.153Z" - }, - { - "x": 5, - "y": 168, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.154Z" - }, - { - "x": 6, - "y": 168, - "type": "TEXT", - "value": "35.1550675", - "last_modified": "2023-02-17T00:02:06.154Z" - }, - { - "x": 7, - "y": 168, - "type": "TEXT", - "value": "-97.47039389", - "last_modified": "2023-02-17T00:02:06.155Z" - }, - { - "x": 0, - "y": 169, - "type": "TEXT", - "value": "166", - "last_modified": "2023-02-17T00:02:06.155Z" - }, - { - "x": 1, - "y": 169, - "type": "TEXT", - "value": "1K5", - "last_modified": "2023-02-17T00:02:06.156Z" - }, - { - "x": 2, - "y": 169, - "type": "TEXT", - "value": "Waynoka Municipal", - "last_modified": "2023-02-17T00:02:06.156Z" - }, - { - "x": 3, - "y": 169, - "type": "TEXT", - "value": "Waynoka", - "last_modified": "2023-02-17T00:02:06.157Z" - }, - { - "x": 4, - "y": 169, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:06.157Z" - }, - { - "x": 5, - "y": 169, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.158Z" - }, - { - "x": 6, - "y": 169, - "type": "TEXT", - "value": "36.56670028", - "last_modified": "2023-02-17T00:02:06.158Z" - }, - { - "x": 7, - "y": 169, - "type": "TEXT", - "value": "-98.85231333", - "last_modified": "2023-02-17T00:02:06.159Z" - }, - { - "x": 0, - "y": 170, - "type": "TEXT", - "value": "167", - "last_modified": "2023-02-17T00:02:06.159Z" - }, - { - "x": 1, - "y": 170, - "type": "TEXT", - "value": "1K9", - "last_modified": "2023-02-17T00:02:06.160Z" - }, - { - "x": 2, - "y": 170, - "type": "TEXT", - "value": "Satanta Municipal", - "last_modified": "2023-02-17T00:02:06.161Z" - }, - { - "x": 3, - "y": 170, - "type": "TEXT", - "value": "Satanta", - "last_modified": "2023-02-17T00:02:06.161Z" - }, - { - "x": 4, - "y": 170, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:06.162Z" - }, - { - "x": 5, - "y": 170, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.162Z" - }, - { - "x": 6, - "y": 170, - "type": "TEXT", - "value": "37.45419111", - "last_modified": "2023-02-17T00:02:06.163Z" - }, - { - "x": 7, - "y": 170, - "type": "TEXT", - "value": "-100.9921119", - "last_modified": "2023-02-17T00:02:06.163Z" - }, - { - "x": 0, - "y": 171, - "type": "TEXT", - "value": "168", - "last_modified": "2023-02-17T00:02:06.164Z" - }, - { - "x": 1, - "y": 171, - "type": "TEXT", - "value": "1L0", - "last_modified": "2023-02-17T00:02:06.164Z" - }, - { - "x": 2, - "y": 171, - "type": "TEXT", - "value": "St. John the Baptist Parish", - "last_modified": "2023-02-17T00:02:06.165Z" - }, - { - "x": 3, - "y": 171, - "type": "TEXT", - "value": "Reserve", - "last_modified": "2023-02-17T00:02:06.165Z" - }, - { - "x": 4, - "y": 171, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:06.166Z" - }, - { - "x": 5, - "y": 171, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.166Z" - }, - { - "x": 6, - "y": 171, - "type": "TEXT", - "value": "30.08720833", - "last_modified": "2023-02-17T00:02:06.167Z" - }, - { - "x": 7, - "y": 171, - "type": "TEXT", - "value": "-90.58266528", - "last_modified": "2023-02-17T00:02:06.167Z" - }, - { - "x": 0, - "y": 172, - "type": "TEXT", - "value": "169", - "last_modified": "2023-02-17T00:02:06.168Z" - }, - { - "x": 1, - "y": 172, - "type": "TEXT", - "value": "1L1", - "last_modified": "2023-02-17T00:02:06.168Z" - }, - { - "x": 2, - "y": 172, - "type": "TEXT", - "value": "Lincoln Co", - "last_modified": "2023-02-17T00:02:06.169Z" - }, - { - "x": 3, - "y": 172, - "type": "TEXT", - "value": "Panaca", - "last_modified": "2023-02-17T00:02:06.169Z" - }, - { - "x": 4, - "y": 172, - "type": "TEXT", - "value": "NV", - "last_modified": "2023-02-17T00:02:06.170Z" - }, - { - "x": 5, - "y": 172, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.170Z" - }, - { - "x": 6, - "y": 172, - "type": "TEXT", - "value": "37.78746444", - "last_modified": "2023-02-17T00:02:06.171Z" - }, - { - "x": 7, - "y": 172, - "type": "TEXT", - "value": "-114.4216567", - "last_modified": "2023-02-17T00:02:06.171Z" - }, - { - "x": 0, - "y": 173, - "type": "TEXT", - "value": "170", - "last_modified": "2023-02-17T00:02:06.172Z" - }, - { - "x": 1, - "y": 173, - "type": "TEXT", - "value": "1L7", - "last_modified": "2023-02-17T00:02:06.172Z" - }, - { - "x": 2, - "y": 173, - "type": "TEXT", - "value": "Escalante Municipal", - "last_modified": "2023-02-17T00:02:06.173Z" - }, - { - "x": 3, - "y": 173, - "type": "TEXT", - "value": "Escalante", - "last_modified": "2023-02-17T00:02:06.173Z" - }, - { - "x": 4, - "y": 173, - "type": "TEXT", - "value": "UT", - "last_modified": "2023-02-17T00:02:06.174Z" - }, - { - "x": 5, - "y": 173, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.174Z" - }, - { - "x": 6, - "y": 173, - "type": "TEXT", - "value": "37.74532639", - "last_modified": "2023-02-17T00:02:06.175Z" - }, - { - "x": 7, - "y": 173, - "type": "TEXT", - "value": "-111.5701653", - "last_modified": "2023-02-17T00:02:06.175Z" - }, - { - "x": 0, - "y": 174, - "type": "TEXT", - "value": "171", - "last_modified": "2023-02-17T00:02:06.176Z" - }, - { - "x": 1, - "y": 174, - "type": "TEXT", - "value": "1L9", - "last_modified": "2023-02-17T00:02:06.176Z" - }, - { - "x": 2, - "y": 174, - "type": "TEXT", - "value": "Parowan", - "last_modified": "2023-02-17T00:02:06.177Z" - }, - { - "x": 3, - "y": 174, - "type": "TEXT", - "value": "Parowan", - "last_modified": "2023-02-17T00:02:06.177Z" - }, - { - "x": 4, - "y": 174, - "type": "TEXT", - "value": "UT", - "last_modified": "2023-02-17T00:02:06.178Z" - }, - { - "x": 5, - "y": 174, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.178Z" - }, - { - "x": 6, - "y": 174, - "type": "TEXT", - "value": "37.85969694", - "last_modified": "2023-02-17T00:02:06.179Z" - }, - { - "x": 7, - "y": 174, - "type": "TEXT", - "value": "-112.816055", - "last_modified": "2023-02-17T00:02:06.179Z" - }, - { - "x": 0, - "y": 175, - "type": "TEXT", - "value": "172", - "last_modified": "2023-02-17T00:02:06.179Z" - }, - { - "x": 1, - "y": 175, - "type": "TEXT", - "value": "1M1", - "last_modified": "2023-02-17T00:02:06.180Z" - }, - { - "x": 2, - "y": 175, - "type": "TEXT", - "value": "North Little Rock Municipal", - "last_modified": "2023-02-17T00:02:06.180Z" - }, - { - "x": 3, - "y": 175, - "type": "TEXT", - "value": "No Lit Rock", - "last_modified": "2023-02-17T00:02:06.181Z" - }, - { - "x": 4, - "y": 175, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:06.181Z" - }, - { - "x": 5, - "y": 175, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.182Z" - }, - { - "x": 6, - "y": 175, - "type": "TEXT", - "value": "34.83398056", - "last_modified": "2023-02-17T00:02:06.182Z" - }, - { - "x": 7, - "y": 175, - "type": "TEXT", - "value": "-92.25792778", - "last_modified": "2023-02-17T00:02:06.183Z" - }, - { - "x": 0, - "y": 176, - "type": "TEXT", - "value": "173", - "last_modified": "2023-02-17T00:02:06.183Z" - }, - { - "x": 1, - "y": 176, - "type": "TEXT", - "value": "1M2", - "last_modified": "2023-02-17T00:02:06.184Z" - }, - { - "x": 2, - "y": 176, - "type": "TEXT", - "value": "Belzoni Municipal", - "last_modified": "2023-02-17T00:02:06.184Z" - }, - { - "x": 3, - "y": 176, - "type": "TEXT", - "value": "Belzoni", - "last_modified": "2023-02-17T00:02:06.185Z" - }, - { - "x": 4, - "y": 176, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:06.185Z" - }, - { - "x": 5, - "y": 176, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.185Z" - }, - { - "x": 6, - "y": 176, - "type": "TEXT", - "value": "33.14518056", - "last_modified": "2023-02-17T00:02:06.186Z" - }, - { - "x": 7, - "y": 176, - "type": "TEXT", - "value": "-90.51528472", - "last_modified": "2023-02-17T00:02:06.186Z" - }, - { - "x": 0, - "y": 177, - "type": "TEXT", - "value": "174", - "last_modified": "2023-02-17T00:02:06.187Z" - }, - { - "x": 1, - "y": 177, - "type": "TEXT", - "value": "1M4", - "last_modified": "2023-02-17T00:02:06.187Z" - }, - { - "x": 2, - "y": 177, - "type": "TEXT", - "value": "Posey", - "last_modified": "2023-02-17T00:02:06.188Z" - }, - { - "x": 3, - "y": 177, - "type": "TEXT", - "value": "Haleyville", - "last_modified": "2023-02-17T00:02:06.188Z" - }, - { - "x": 4, - "y": 177, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:06.189Z" - }, - { - "x": 5, - "y": 177, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.189Z" - }, - { - "x": 6, - "y": 177, - "type": "TEXT", - "value": "34.28034806", - "last_modified": "2023-02-17T00:02:06.189Z" - }, - { - "x": 7, - "y": 177, - "type": "TEXT", - "value": "-87.60044139", - "last_modified": "2023-02-17T00:02:06.190Z" - }, - { - "x": 0, - "y": 178, - "type": "TEXT", - "value": "175", - "last_modified": "2023-02-17T00:02:06.190Z" - }, - { - "x": 1, - "y": 178, - "type": "TEXT", - "value": "1M5", - "last_modified": "2023-02-17T00:02:06.191Z" - }, - { - "x": 2, - "y": 178, - "type": "TEXT", - "value": "Portland Municipal", - "last_modified": "2023-02-17T00:02:06.191Z" - }, - { - "x": 3, - "y": 178, - "type": "TEXT", - "value": "Portland", - "last_modified": "2023-02-17T00:02:06.192Z" - }, - { - "x": 4, - "y": 178, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:06.192Z" - }, - { - "x": 5, - "y": 178, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.193Z" - }, - { - "x": 6, - "y": 178, - "type": "TEXT", - "value": "36.59287528", - "last_modified": "2023-02-17T00:02:06.193Z" - }, - { - "x": 7, - "y": 178, - "type": "TEXT", - "value": "-86.47691028", - "last_modified": "2023-02-17T00:02:06.193Z" - }, - { - "x": 0, - "y": 179, - "type": "TEXT", - "value": "176", - "last_modified": "2023-02-17T00:02:06.194Z" - }, - { - "x": 1, - "y": 179, - "type": "TEXT", - "value": "1M7", - "last_modified": "2023-02-17T00:02:06.194Z" - }, - { - "x": 2, - "y": 179, - "type": "TEXT", - "value": "Fulton", - "last_modified": "2023-02-17T00:02:06.195Z" - }, - { - "x": 3, - "y": 179, - "type": "TEXT", - "value": "Fulton", - "last_modified": "2023-02-17T00:02:06.195Z" - }, - { - "x": 4, - "y": 179, - "type": "TEXT", - "value": "KY", - "last_modified": "2023-02-17T00:02:06.196Z" - }, - { - "x": 5, - "y": 179, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.196Z" - }, - { - "x": 6, - "y": 179, - "type": "TEXT", - "value": "36.52589417", - "last_modified": "2023-02-17T00:02:06.196Z" - }, - { - "x": 7, - "y": 179, - "type": "TEXT", - "value": "-88.91561611", - "last_modified": "2023-02-17T00:02:06.197Z" - }, - { - "x": 0, - "y": 180, - "type": "TEXT", - "value": "177", - "last_modified": "2023-02-17T00:02:06.197Z" - }, - { - "x": 1, - "y": 180, - "type": "TEXT", - "value": "1MO", - "last_modified": "2023-02-17T00:02:06.198Z" - }, - { - "x": 2, - "y": 180, - "type": "TEXT", - "value": "Mountain Grove Memorial", - "last_modified": "2023-02-17T00:02:06.198Z" - }, - { - "x": 3, - "y": 180, - "type": "TEXT", - "value": "Mountain Grove", - "last_modified": "2023-02-17T00:02:06.199Z" - }, - { - "x": 4, - "y": 180, - "type": "TEXT", - "value": "MO", - "last_modified": "2023-02-17T00:02:06.199Z" - }, - { - "x": 5, - "y": 180, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.199Z" - }, - { - "x": 6, - "y": 180, - "type": "TEXT", - "value": "37.12071889", - "last_modified": "2023-02-17T00:02:06.200Z" - }, - { - "x": 7, - "y": 180, - "type": "TEXT", - "value": "-92.311245", - "last_modified": "2023-02-17T00:02:06.200Z" - }, - { - "x": 0, - "y": 181, - "type": "TEXT", - "value": "178", - "last_modified": "2023-02-17T00:02:06.201Z" - }, - { - "x": 1, - "y": 181, - "type": "TEXT", - "value": "1N2", - "last_modified": "2023-02-17T00:02:06.201Z" - }, - { - "x": 2, - "y": 181, - "type": "TEXT", - "value": "Spadaro", - "last_modified": "2023-02-17T00:02:06.201Z" - }, - { - "x": 3, - "y": 181, - "type": "TEXT", - "value": "East Moriches", - "last_modified": "2023-02-17T00:02:06.202Z" - }, - { - "x": 4, - "y": 181, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:06.202Z" - }, - { - "x": 5, - "y": 181, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.203Z" - }, - { - "x": 6, - "y": 181, - "type": "TEXT", - "value": "40.82787639", - "last_modified": "2023-02-17T00:02:06.203Z" - }, - { - "x": 7, - "y": 181, - "type": "TEXT", - "value": "-72.74871083", - "last_modified": "2023-02-17T00:02:06.203Z" - }, - { - "x": 0, - "y": 182, - "type": "TEXT", - "value": "179", - "last_modified": "2023-02-17T00:02:06.204Z" - }, - { - "x": 1, - "y": 182, - "type": "TEXT", - "value": "1N4", - "last_modified": "2023-02-17T00:02:06.204Z" - }, - { - "x": 2, - "y": 182, - "type": "TEXT", - "value": "Woodbine Muni", - "last_modified": "2023-02-17T00:02:06.205Z" - }, - { - "x": 3, - "y": 182, - "type": "TEXT", - "value": "Woodbine", - "last_modified": "2023-02-17T00:02:06.205Z" - }, - { - "x": 4, - "y": 182, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:06.205Z" - }, - { - "x": 5, - "y": 182, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.206Z" - }, - { - "x": 6, - "y": 182, - "type": "TEXT", - "value": "39.21915", - "last_modified": "2023-02-17T00:02:06.206Z" - }, - { - "x": 7, - "y": 182, - "type": "TEXT", - "value": "-74.794765", - "last_modified": "2023-02-17T00:02:06.207Z" - }, - { - "x": 0, - "y": 183, - "type": "TEXT", - "value": "180", - "last_modified": "2023-02-17T00:02:06.207Z" - }, - { - "x": 1, - "y": 183, - "type": "TEXT", - "value": "1N7", - "last_modified": "2023-02-17T00:02:06.207Z" - }, - { - "x": 2, - "y": 183, - "type": "TEXT", - "value": "Blairstown", - "last_modified": "2023-02-17T00:02:06.208Z" - }, - { - "x": 3, - "y": 183, - "type": "TEXT", - "value": "Blairstown", - "last_modified": "2023-02-17T00:02:06.208Z" - }, - { - "x": 4, - "y": 183, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:06.209Z" - }, - { - "x": 5, - "y": 183, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.209Z" - }, - { - "x": 6, - "y": 183, - "type": "TEXT", - "value": "40.97114556", - "last_modified": "2023-02-17T00:02:06.209Z" - }, - { - "x": 7, - "y": 183, - "type": "TEXT", - "value": "-74.99747556", - "last_modified": "2023-02-17T00:02:06.210Z" - }, - { - "x": 0, - "y": 184, - "type": "TEXT", - "value": "181", - "last_modified": "2023-02-17T00:02:06.210Z" - }, - { - "x": 1, - "y": 184, - "type": "TEXT", - "value": "1N9", - "last_modified": "2023-02-17T00:02:06.210Z" - }, - { - "x": 2, - "y": 184, - "type": "TEXT", - "value": "Allentown Queen City Muni", - "last_modified": "2023-02-17T00:02:06.211Z" - }, - { - "x": 3, - "y": 184, - "type": "TEXT", - "value": "Allentown", - "last_modified": "2023-02-17T00:02:06.211Z" - }, - { - "x": 4, - "y": 184, - "type": "TEXT", - "value": "PA", - "last_modified": "2023-02-17T00:02:06.212Z" - }, - { - "x": 5, - "y": 184, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.212Z" - }, - { - "x": 6, - "y": 184, - "type": "TEXT", - "value": "40.57027778", - "last_modified": "2023-02-17T00:02:06.212Z" - }, - { - "x": 7, - "y": 184, - "type": "TEXT", - "value": "-75.48830556", - "last_modified": "2023-02-17T00:02:06.213Z" - }, - { - "x": 0, - "y": 185, - "type": "TEXT", - "value": "182", - "last_modified": "2023-02-17T00:02:06.213Z" - }, - { - "x": 1, - "y": 185, - "type": "TEXT", - "value": "1ND3", - "last_modified": "2023-02-17T00:02:06.214Z" - }, - { - "x": 2, - "y": 185, - "type": "TEXT", - "value": "Hamry", - "last_modified": "2023-02-17T00:02:06.214Z" - }, - { - "x": 3, - "y": 185, - "type": "TEXT", - "value": "Kindred", - "last_modified": "2023-02-17T00:02:06.214Z" - }, - { - "x": 4, - "y": 185, - "type": "TEXT", - "value": "ND", - "last_modified": "2023-02-17T00:02:06.215Z" - }, - { - "x": 5, - "y": 185, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.215Z" - }, - { - "x": 6, - "y": 185, - "type": "TEXT", - "value": "46.6485775", - "last_modified": "2023-02-17T00:02:06.215Z" - }, - { - "x": 7, - "y": 185, - "type": "TEXT", - "value": "-97.00564306", - "last_modified": "2023-02-17T00:02:06.216Z" - }, - { - "x": 0, - "y": 186, - "type": "TEXT", - "value": "183", - "last_modified": "2023-02-17T00:02:06.216Z" - }, - { - "x": 1, - "y": 186, - "type": "TEXT", - "value": "1O1", - "last_modified": "2023-02-17T00:02:06.216Z" - }, - { - "x": 2, - "y": 186, - "type": "TEXT", - "value": "Grandfield Municipal", - "last_modified": "2023-02-17T00:02:06.217Z" - }, - { - "x": 3, - "y": 186, - "type": "TEXT", - "value": "Grandfield", - "last_modified": "2023-02-17T00:02:06.217Z" - }, - { - "x": 4, - "y": 186, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:06.218Z" - }, - { - "x": 5, - "y": 186, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.218Z" - }, - { - "x": 6, - "y": 186, - "type": "TEXT", - "value": "34.23758944", - "last_modified": "2023-02-17T00:02:06.219Z" - }, - { - "x": 7, - "y": 186, - "type": "TEXT", - "value": "-98.74200917", - "last_modified": "2023-02-17T00:02:06.219Z" - }, - { - "x": 0, - "y": 187, - "type": "TEXT", - "value": "184", - "last_modified": "2023-02-17T00:02:06.219Z" - }, - { - "x": 1, - "y": 187, - "type": "TEXT", - "value": "1O2", - "last_modified": "2023-02-17T00:02:06.220Z" - }, - { - "x": 2, - "y": 187, - "type": "TEXT", - "value": "Lampson", - "last_modified": "2023-02-17T00:02:06.220Z" - }, - { - "x": 3, - "y": 187, - "type": "TEXT", - "value": "Lakeport", - "last_modified": "2023-02-17T00:02:06.220Z" - }, - { - "x": 4, - "y": 187, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:06.221Z" - }, - { - "x": 5, - "y": 187, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.221Z" - }, - { - "x": 6, - "y": 187, - "type": "TEXT", - "value": "38.99017472", - "last_modified": "2023-02-17T00:02:06.221Z" - }, - { - "x": 7, - "y": 187, - "type": "TEXT", - "value": "-122.8997175", - "last_modified": "2023-02-17T00:02:06.222Z" - }, - { - "x": 0, - "y": 188, - "type": "TEXT", - "value": "185", - "last_modified": "2023-02-17T00:02:06.222Z" - }, - { - "x": 1, - "y": 188, - "type": "TEXT", - "value": "1O3", - "last_modified": "2023-02-17T00:02:06.222Z" - }, - { - "x": 2, - "y": 188, - "type": "TEXT", - "value": "Lodi", - "last_modified": "2023-02-17T00:02:06.223Z" - }, - { - "x": 3, - "y": 188, - "type": "TEXT", - "value": "Lodi", - "last_modified": "2023-02-17T00:02:06.223Z" - }, - { - "x": 4, - "y": 188, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:06.224Z" - }, - { - "x": 5, - "y": 188, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.224Z" - }, - { - "x": 6, - "y": 188, - "type": "TEXT", - "value": "38.20241667", - "last_modified": "2023-02-17T00:02:06.224Z" - }, - { - "x": 7, - "y": 188, - "type": "TEXT", - "value": "-121.2684167", - "last_modified": "2023-02-17T00:02:06.225Z" - }, - { - "x": 0, - "y": 189, - "type": "TEXT", - "value": "186", - "last_modified": "2023-02-17T00:02:06.225Z" - }, - { - "x": 1, - "y": 189, - "type": "TEXT", - "value": "1O4", - "last_modified": "2023-02-17T00:02:06.225Z" - }, - { - "x": 2, - "y": 189, - "type": "TEXT", - "value": "Thomas Municipal", - "last_modified": "2023-02-17T00:02:06.226Z" - }, - { - "x": 3, - "y": 189, - "type": "TEXT", - "value": "Thomas", - "last_modified": "2023-02-17T00:02:06.226Z" - }, - { - "x": 4, - "y": 189, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:06.226Z" - }, - { - "x": 5, - "y": 189, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.227Z" - }, - { - "x": 6, - "y": 189, - "type": "TEXT", - "value": "35.73338222", - "last_modified": "2023-02-17T00:02:06.227Z" - }, - { - "x": 7, - "y": 189, - "type": "TEXT", - "value": "-98.73063833", - "last_modified": "2023-02-17T00:02:06.227Z" - }, - { - "x": 0, - "y": 190, - "type": "TEXT", - "value": "187", - "last_modified": "2023-02-17T00:02:06.228Z" - }, - { - "x": 1, - "y": 190, - "type": "TEXT", - "value": "1O6", - "last_modified": "2023-02-17T00:02:06.228Z" - }, - { - "x": 2, - "y": 190, - "type": "TEXT", - "value": "Dunsmuir Municipal-Mott", - "last_modified": "2023-02-17T00:02:06.228Z" - }, - { - "x": 3, - "y": 190, - "type": "TEXT", - "value": "Dunsmuir", - "last_modified": "2023-02-17T00:02:06.229Z" - }, - { - "x": 4, - "y": 190, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:06.229Z" - }, - { - "x": 5, - "y": 190, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.229Z" - }, - { - "x": 6, - "y": 190, - "type": "TEXT", - "value": "41.26320889", - "last_modified": "2023-02-17T00:02:06.230Z" - }, - { - "x": 7, - "y": 190, - "type": "TEXT", - "value": "-122.2719528", - "last_modified": "2023-02-17T00:02:06.230Z" - }, - { - "x": 0, - "y": 191, - "type": "TEXT", - "value": "188", - "last_modified": "2023-02-17T00:02:06.230Z" - }, - { - "x": 1, - "y": 191, - "type": "TEXT", - "value": "1R1", - "last_modified": "2023-02-17T00:02:06.230Z" - }, - { - "x": 2, - "y": 191, - "type": "TEXT", - "value": "Jena", - "last_modified": "2023-02-17T00:02:06.231Z" - }, - { - "x": 3, - "y": 191, - "type": "TEXT", - "value": "Jena", - "last_modified": "2023-02-17T00:02:06.231Z" - }, - { - "x": 4, - "y": 191, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:06.231Z" - }, - { - "x": 5, - "y": 191, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.232Z" - }, - { - "x": 6, - "y": 191, - "type": "TEXT", - "value": "31.671005", - "last_modified": "2023-02-17T00:02:06.232Z" - }, - { - "x": 7, - "y": 191, - "type": "TEXT", - "value": "-92.15846722", - "last_modified": "2023-02-17T00:02:06.232Z" - }, - { - "x": 0, - "y": 192, - "type": "TEXT", - "value": "189", - "last_modified": "2023-02-17T00:02:06.233Z" - }, - { - "x": 1, - "y": 192, - "type": "TEXT", - "value": "1R7", - "last_modified": "2023-02-17T00:02:06.233Z" - }, - { - "x": 2, - "y": 192, - "type": "TEXT", - "value": "Brookhaven-Lincoln County", - "last_modified": "2023-02-17T00:02:06.233Z" - }, - { - "x": 3, - "y": 192, - "type": "TEXT", - "value": "Brookhaven", - "last_modified": "2023-02-17T00:02:06.234Z" - }, - { - "x": 4, - "y": 192, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:06.234Z" - }, - { - "x": 5, - "y": 192, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.234Z" - }, - { - "x": 6, - "y": 192, - "type": "TEXT", - "value": "31.6058475", - "last_modified": "2023-02-17T00:02:06.235Z" - }, - { - "x": 7, - "y": 192, - "type": "TEXT", - "value": "-90.40931583", - "last_modified": "2023-02-17T00:02:06.235Z" - }, - { - "x": 0, - "y": 193, - "type": "TEXT", - "value": "190", - "last_modified": "2023-02-17T00:02:06.235Z" - }, - { - "x": 1, - "y": 193, - "type": "TEXT", - "value": "1R8", - "last_modified": "2023-02-17T00:02:06.236Z" - }, - { - "x": 2, - "y": 193, - "type": "TEXT", - "value": "Bay Minette Municipal", - "last_modified": "2023-02-17T00:02:06.236Z" - }, - { - "x": 3, - "y": 193, - "type": "TEXT", - "value": "Bay Minette", - "last_modified": "2023-02-17T00:02:06.236Z" - }, - { - "x": 4, - "y": 193, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:06.236Z" - }, - { - "x": 5, - "y": 193, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.237Z" - }, - { - "x": 6, - "y": 193, - "type": "TEXT", - "value": "30.87046278", - "last_modified": "2023-02-17T00:02:06.237Z" - }, - { - "x": 7, - "y": 193, - "type": "TEXT", - "value": "-87.81738167", - "last_modified": "2023-02-17T00:02:06.237Z" - }, - { - "x": 0, - "y": 194, - "type": "TEXT", - "value": "191", - "last_modified": "2023-02-17T00:02:06.238Z" - }, - { - "x": 1, - "y": 194, - "type": "TEXT", - "value": "1S0", - "last_modified": "2023-02-17T00:02:06.238Z" - }, - { - "x": 2, - "y": 194, - "type": "TEXT", - "value": "Pierce County", - "last_modified": "2023-02-17T00:02:06.238Z" - }, - { - "x": 3, - "y": 194, - "type": "TEXT", - "value": "Puyallup", - "last_modified": "2023-02-17T00:02:06.239Z" - }, - { - "x": 4, - "y": 194, - "type": "TEXT", - "value": "WA", - "last_modified": "2023-02-17T00:02:06.239Z" - }, - { - "x": 5, - "y": 194, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.239Z" - }, - { - "x": 6, - "y": 194, - "type": "TEXT", - "value": "47.10391667", - "last_modified": "2023-02-17T00:02:06.239Z" - }, - { - "x": 7, - "y": 194, - "type": "TEXT", - "value": "-122.2871944", - "last_modified": "2023-02-17T00:02:06.240Z" - }, - { - "x": 0, - "y": 195, - "type": "TEXT", - "value": "192", - "last_modified": "2023-02-17T00:02:06.240Z" - }, - { - "x": 1, - "y": 195, - "type": "TEXT", - "value": "1S3", - "last_modified": "2023-02-17T00:02:06.240Z" - }, - { - "x": 2, - "y": 195, - "type": "TEXT", - "value": "Tillitt", - "last_modified": "2023-02-17T00:02:06.241Z" - }, - { - "x": 3, - "y": 195, - "type": "TEXT", - "value": "Forsyth", - "last_modified": "2023-02-17T00:02:06.241Z" - }, - { - "x": 4, - "y": 195, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:06.241Z" - }, - { - "x": 5, - "y": 195, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.241Z" - }, - { - "x": 6, - "y": 195, - "type": "TEXT", - "value": "46.27110639", - "last_modified": "2023-02-17T00:02:06.242Z" - }, - { - "x": 7, - "y": 195, - "type": "TEXT", - "value": "-106.6239206", - "last_modified": "2023-02-17T00:02:06.242Z" - }, - { - "x": 0, - "y": 196, - "type": "TEXT", - "value": "193", - "last_modified": "2023-02-17T00:02:06.242Z" - }, - { - "x": 1, - "y": 196, - "type": "TEXT", - "value": "1S5", - "last_modified": "2023-02-17T00:02:06.243Z" - }, - { - "x": 2, - "y": 196, - "type": "TEXT", - "value": "Sunnyside Municipal", - "last_modified": "2023-02-17T00:02:06.243Z" - }, - { - "x": 3, - "y": 196, - "type": "TEXT", - "value": "Sunnyside", - "last_modified": "2023-02-17T00:02:06.243Z" - }, - { - "x": 4, - "y": 196, - "type": "TEXT", - "value": "WA", - "last_modified": "2023-02-17T00:02:06.243Z" - }, - { - "x": 5, - "y": 196, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.244Z" - }, - { - "x": 6, - "y": 196, - "type": "TEXT", - "value": "46.32763139", - "last_modified": "2023-02-17T00:02:06.244Z" - }, - { - "x": 7, - "y": 196, - "type": "TEXT", - "value": "-119.9705964", - "last_modified": "2023-02-17T00:02:06.244Z" - }, - { - "x": 0, - "y": 197, - "type": "TEXT", - "value": "194", - "last_modified": "2023-02-17T00:02:06.245Z" - }, - { - "x": 1, - "y": 197, - "type": "TEXT", - "value": "1S6", - "last_modified": "2023-02-17T00:02:06.245Z" - }, - { - "x": 2, - "y": 197, - "type": "TEXT", - "value": "Priest River Muni", - "last_modified": "2023-02-17T00:02:06.245Z" - }, - { - "x": 3, - "y": 197, - "type": "TEXT", - "value": "Priest River", - "last_modified": "2023-02-17T00:02:06.245Z" - }, - { - "x": 4, - "y": 197, - "type": "TEXT", - "value": "ID", - "last_modified": "2023-02-17T00:02:06.246Z" - }, - { - "x": 5, - "y": 197, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.246Z" - }, - { - "x": 6, - "y": 197, - "type": "TEXT", - "value": "48.19018611", - "last_modified": "2023-02-17T00:02:06.246Z" - }, - { - "x": 7, - "y": 197, - "type": "TEXT", - "value": "-116.9093644", - "last_modified": "2023-02-17T00:02:06.246Z" - }, - { - "x": 0, - "y": 198, - "type": "TEXT", - "value": "195", - "last_modified": "2023-02-17T00:02:06.247Z" - }, - { - "x": 1, - "y": 198, - "type": "TEXT", - "value": "1U7", - "last_modified": "2023-02-17T00:02:06.247Z" - }, - { - "x": 2, - "y": 198, - "type": "TEXT", - "value": "Bear Lake County", - "last_modified": "2023-02-17T00:02:06.247Z" - }, - { - "x": 3, - "y": 198, - "type": "TEXT", - "value": "Paris", - "last_modified": "2023-02-17T00:02:06.247Z" - }, - { - "x": 4, - "y": 198, - "type": "TEXT", - "value": "ID", - "last_modified": "2023-02-17T00:02:06.248Z" - }, - { - "x": 5, - "y": 198, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.248Z" - }, - { - "x": 6, - "y": 198, - "type": "TEXT", - "value": "42.24714972", - "last_modified": "2023-02-17T00:02:06.248Z" - }, - { - "x": 7, - "y": 198, - "type": "TEXT", - "value": "-111.33826", - "last_modified": "2023-02-17T00:02:06.249Z" - }, - { - "x": 0, - "y": 199, - "type": "TEXT", - "value": "196", - "last_modified": "2023-02-17T00:02:06.249Z" - }, - { - "x": 1, - "y": 199, - "type": "TEXT", - "value": "1V0", - "last_modified": "2023-02-17T00:02:06.249Z" - }, - { - "x": 2, - "y": 199, - "type": "TEXT", - "value": "Navajo State Park", - "last_modified": "2023-02-17T00:02:06.249Z" - }, - { - "x": 3, - "y": 199, - "type": "TEXT", - "value": "Navajo Dam", - "last_modified": "2023-02-17T00:02:06.250Z" - }, - { - "x": 4, - "y": 199, - "type": "TEXT", - "value": "NM", - "last_modified": "2023-02-17T00:02:06.250Z" - }, - { - "x": 5, - "y": 199, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.250Z" - }, - { - "x": 6, - "y": 199, - "type": "TEXT", - "value": "36.80833833", - "last_modified": "2023-02-17T00:02:06.250Z" - }, - { - "x": 7, - "y": 199, - "type": "TEXT", - "value": "-107.6514444", - "last_modified": "2023-02-17T00:02:06.251Z" - }, - { - "x": 0, - "y": 200, - "type": "TEXT", - "value": "197", - "last_modified": "2023-02-17T00:02:06.251Z" - }, - { - "x": 1, - "y": 200, - "type": "TEXT", - "value": "1V2", - "last_modified": "2023-02-17T00:02:06.251Z" - }, - { - "x": 2, - "y": 200, - "type": "TEXT", - "value": "Grant County", - "last_modified": "2023-02-17T00:02:06.251Z" - }, - { - "x": 3, - "y": 200, - "type": "TEXT", - "value": "Hyannis", - "last_modified": "2023-02-17T00:02:06.252Z" - }, - { - "x": 4, - "y": 200, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:06.252Z" - }, - { - "x": 5, - "y": 200, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.252Z" - }, - { - "x": 6, - "y": 200, - "type": "TEXT", - "value": "42.00942944", - "last_modified": "2023-02-17T00:02:06.252Z" - }, - { - "x": 7, - "y": 200, - "type": "TEXT", - "value": "-101.7693439", - "last_modified": "2023-02-17T00:02:06.253Z" - }, - { - "x": 0, - "y": 201, - "type": "TEXT", - "value": "198", - "last_modified": "2023-02-17T00:02:06.253Z" - }, - { - "x": 1, - "y": 201, - "type": "TEXT", - "value": "1V5", - "last_modified": "2023-02-17T00:02:06.253Z" - }, - { - "x": 2, - "y": 201, - "type": "TEXT", - "value": "Boulder Muni", - "last_modified": "2023-02-17T00:02:06.253Z" - }, - { - "x": 3, - "y": 201, - "type": "TEXT", - "value": "Boulder", - "last_modified": "2023-02-17T00:02:06.254Z" - }, - { - "x": 4, - "y": 201, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:06.254Z" - }, - { - "x": 5, - "y": 201, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.254Z" - }, - { - "x": 6, - "y": 201, - "type": "TEXT", - "value": "40.03942972", - "last_modified": "2023-02-17T00:02:06.254Z" - }, - { - "x": 7, - "y": 201, - "type": "TEXT", - "value": "-105.2258217", - "last_modified": "2023-02-17T00:02:06.255Z" - }, - { - "x": 0, - "y": 202, - "type": "TEXT", - "value": "199", - "last_modified": "2023-02-17T00:02:06.255Z" - }, - { - "x": 1, - "y": 202, - "type": "TEXT", - "value": "1V6", - "last_modified": "2023-02-17T00:02:06.255Z" - }, - { - "x": 2, - "y": 202, - "type": "TEXT", - "value": "Fremont County", - "last_modified": "2023-02-17T00:02:06.255Z" - }, - { - "x": 3, - "y": 202, - "type": "TEXT", - "value": "Canon City", - "last_modified": "2023-02-17T00:02:06.256Z" - }, - { - "x": 4, - "y": 202, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:06.256Z" - }, - { - "x": 5, - "y": 202, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.256Z" - }, - { - "x": 6, - "y": 202, - "type": "TEXT", - "value": "38.42838111", - "last_modified": "2023-02-17T00:02:06.256Z" - }, - { - "x": 7, - "y": 202, - "type": "TEXT", - "value": "-105.1054994", - "last_modified": "2023-02-17T00:02:06.257Z" - }, - { - "x": 0, - "y": 203, - "type": "TEXT", - "value": "200", - "last_modified": "2023-02-17T00:02:06.257Z" - }, - { - "x": 1, - "y": 203, - "type": "TEXT", - "value": "1V9", - "last_modified": "2023-02-17T00:02:06.257Z" - }, - { - "x": 2, - "y": 203, - "type": "TEXT", - "value": "Blake", - "last_modified": "2023-02-17T00:02:06.257Z" - }, - { - "x": 3, - "y": 203, - "type": "TEXT", - "value": "Delta", - "last_modified": "2023-02-17T00:02:06.257Z" - }, - { - "x": 4, - "y": 203, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:06.258Z" - }, - { - "x": 5, - "y": 203, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.258Z" - }, - { - "x": 6, - "y": 203, - "type": "TEXT", - "value": "38.78539722", - "last_modified": "2023-02-17T00:02:06.258Z" - }, - { - "x": 7, - "y": 203, - "type": "TEXT", - "value": "-108.0636611", - "last_modified": "2023-02-17T00:02:06.258Z" - }, - { - "x": 0, - "y": 204, - "type": "TEXT", - "value": "201", - "last_modified": "2023-02-17T00:02:06.259Z" - }, - { - "x": 1, - "y": 204, - "type": "TEXT", - "value": "20A", - "last_modified": "2023-02-17T00:02:06.259Z" - }, - { - "x": 2, - "y": 204, - "type": "TEXT", - "value": "Robbins", - "last_modified": "2023-02-17T00:02:06.259Z" - }, - { - "x": 3, - "y": 204, - "type": "TEXT", - "value": "Oneonta", - "last_modified": "2023-02-17T00:02:06.259Z" - }, - { - "x": 4, - "y": 204, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:06.260Z" - }, - { - "x": 5, - "y": 204, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.260Z" - }, - { - "x": 6, - "y": 204, - "type": "TEXT", - "value": "33.97231972", - "last_modified": "2023-02-17T00:02:06.260Z" - }, - { - "x": 7, - "y": 204, - "type": "TEXT", - "value": "-86.37942722", - "last_modified": "2023-02-17T00:02:06.260Z" - }, - { - "x": 0, - "y": 205, - "type": "TEXT", - "value": "202", - "last_modified": "2023-02-17T00:02:06.261Z" - }, - { - "x": 1, - "y": 205, - "type": "TEXT", - "value": "20M", - "last_modified": "2023-02-17T00:02:06.261Z" - }, - { - "x": 2, - "y": 205, - "type": "TEXT", - "value": "Macon Municipal", - "last_modified": "2023-02-17T00:02:06.261Z" - }, - { - "x": 3, - "y": 205, - "type": "TEXT", - "value": "Macon", - "last_modified": "2023-02-17T00:02:06.261Z" - }, - { - "x": 4, - "y": 205, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:06.261Z" - }, - { - "x": 5, - "y": 205, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.262Z" - }, - { - "x": 6, - "y": 205, - "type": "TEXT", - "value": "33.13345889", - "last_modified": "2023-02-17T00:02:06.262Z" - }, - { - "x": 7, - "y": 205, - "type": "TEXT", - "value": "-88.53559806", - "last_modified": "2023-02-17T00:02:06.262Z" - }, - { - "x": 0, - "y": 206, - "type": "TEXT", - "value": "203", - "last_modified": "2023-02-17T00:02:06.262Z" - }, - { - "x": 1, - "y": 206, - "type": "TEXT", - "value": "20N", - "last_modified": "2023-02-17T00:02:06.263Z" - }, - { - "x": 2, - "y": 206, - "type": "TEXT", - "value": "Kingston-Ulster", - "last_modified": "2023-02-17T00:02:06.263Z" - }, - { - "x": 3, - "y": 206, - "type": "TEXT", - "value": "Kingston", - "last_modified": "2023-02-17T00:02:06.263Z" - }, - { - "x": 4, - "y": 206, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:06.263Z" - }, - { - "x": 5, - "y": 206, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.263Z" - }, - { - "x": 6, - "y": 206, - "type": "TEXT", - "value": "41.9852525", - "last_modified": "2023-02-17T00:02:06.264Z" - }, - { - "x": 7, - "y": 206, - "type": "TEXT", - "value": "-73.96409722", - "last_modified": "2023-02-17T00:02:06.264Z" - }, - { - "x": 0, - "y": 207, - "type": "TEXT", - "value": "204", - "last_modified": "2023-02-17T00:02:06.264Z" - }, - { - "x": 1, - "y": 207, - "type": "TEXT", - "value": "20U", - "last_modified": "2023-02-17T00:02:06.264Z" - }, - { - "x": 2, - "y": 207, - "type": "TEXT", - "value": "Beach", - "last_modified": "2023-02-17T00:02:06.264Z" - }, - { - "x": 3, - "y": 207, - "type": "TEXT", - "value": "Beach", - "last_modified": "2023-02-17T00:02:06.265Z" - }, - { - "x": 4, - "y": 207, - "type": "TEXT", - "value": "ND", - "last_modified": "2023-02-17T00:02:06.265Z" - }, - { - "x": 5, - "y": 207, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.265Z" - }, - { - "x": 6, - "y": 207, - "type": "TEXT", - "value": "46.92362444", - "last_modified": "2023-02-17T00:02:06.265Z" - }, - { - "x": 7, - "y": 207, - "type": "TEXT", - "value": "-103.9785389", - "last_modified": "2023-02-17T00:02:06.265Z" - }, - { - "x": 0, - "y": 208, - "type": "TEXT", - "value": "205", - "last_modified": "2023-02-17T00:02:06.266Z" - }, - { - "x": 1, - "y": 208, - "type": "TEXT", - "value": "20V", - "last_modified": "2023-02-17T00:02:06.266Z" - }, - { - "x": 2, - "y": 208, - "type": "TEXT", - "value": "McElroy Airfield", - "last_modified": "2023-02-17T00:02:06.266Z" - }, - { - "x": 3, - "y": 208, - "type": "TEXT", - "value": "Kremmling", - "last_modified": "2023-02-17T00:02:06.266Z" - }, - { - "x": 4, - "y": 208, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:06.266Z" - }, - { - "x": 5, - "y": 208, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.267Z" - }, - { - "x": 6, - "y": 208, - "type": "TEXT", - "value": "40.05367972", - "last_modified": "2023-02-17T00:02:06.267Z" - }, - { - "x": 7, - "y": 208, - "type": "TEXT", - "value": "-106.3689467", - "last_modified": "2023-02-17T00:02:06.267Z" - }, - { - "x": 0, - "y": 209, - "type": "TEXT", - "value": "206", - "last_modified": "2023-02-17T00:02:06.267Z" - }, - { - "x": 1, - "y": 209, - "type": "TEXT", - "value": "21D", - "last_modified": "2023-02-17T00:02:06.267Z" - }, - { - "x": 2, - "y": 209, - "type": "TEXT", - "value": "Lake Elmo", - "last_modified": "2023-02-17T00:02:06.268Z" - }, - { - "x": 3, - "y": 209, - "type": "TEXT", - "value": "St Paul", - "last_modified": "2023-02-17T00:02:06.268Z" - }, - { - "x": 4, - "y": 209, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:06.268Z" - }, - { - "x": 5, - "y": 209, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.268Z" - }, - { - "x": 6, - "y": 209, - "type": "TEXT", - "value": "44.99748861", - "last_modified": "2023-02-17T00:02:06.268Z" - }, - { - "x": 7, - "y": 209, - "type": "TEXT", - "value": "-92.85568111", - "last_modified": "2023-02-17T00:02:06.269Z" - }, - { - "x": 0, - "y": 210, - "type": "TEXT", - "value": "207", - "last_modified": "2023-02-17T00:02:06.269Z" - }, - { - "x": 1, - "y": 210, - "type": "TEXT", - "value": "21F", - "last_modified": "2023-02-17T00:02:06.269Z" - }, - { - "x": 2, - "y": 210, - "type": "TEXT", - "value": "Jacksboro Municipal", - "last_modified": "2023-02-17T00:02:06.269Z" - }, - { - "x": 3, - "y": 210, - "type": "TEXT", - "value": "Jacksboro", - "last_modified": "2023-02-17T00:02:06.269Z" - }, - { - "x": 4, - "y": 210, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:06.270Z" - }, - { - "x": 5, - "y": 210, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.270Z" - }, - { - "x": 6, - "y": 210, - "type": "TEXT", - "value": "33.228725", - "last_modified": "2023-02-17T00:02:06.270Z" - }, - { - "x": 7, - "y": 210, - "type": "TEXT", - "value": "-98.14671083", - "last_modified": "2023-02-17T00:02:06.270Z" - }, - { - "x": 0, - "y": 211, - "type": "TEXT", - "value": "208", - "last_modified": "2023-02-17T00:02:06.270Z" - }, - { - "x": 1, - "y": 211, - "type": "TEXT", - "value": "22B", - "last_modified": "2023-02-17T00:02:06.271Z" - }, - { - "x": 2, - "y": 211, - "type": "TEXT", - "value": "Mountain Meadow Airstrip", - "last_modified": "2023-02-17T00:02:06.271Z" - }, - { - "x": 3, - "y": 211, - "type": "TEXT", - "value": "Burlington", - "last_modified": "2023-02-17T00:02:06.271Z" - }, - { - "x": 4, - "y": 211, - "type": "TEXT", - "value": "CT", - "last_modified": "2023-02-17T00:02:06.271Z" - }, - { - "x": 5, - "y": 211, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.271Z" - }, - { - "x": 6, - "y": 211, - "type": "TEXT", - "value": "41.77287528", - "last_modified": "2023-02-17T00:02:06.271Z" - }, - { - "x": 7, - "y": 211, - "type": "TEXT", - "value": "-73.01121667", - "last_modified": "2023-02-17T00:02:06.272Z" - }, - { - "x": 0, - "y": 212, - "type": "TEXT", - "value": "209", - "last_modified": "2023-02-17T00:02:06.272Z" - }, - { - "x": 1, - "y": 212, - "type": "TEXT", - "value": "22I", - "last_modified": "2023-02-17T00:02:06.272Z" - }, - { - "x": 2, - "y": 212, - "type": "TEXT", - "value": "Vinton County", - "last_modified": "2023-02-17T00:02:06.272Z" - }, - { - "x": 3, - "y": 212, - "type": "TEXT", - "value": "McArthur", - "last_modified": "2023-02-17T00:02:06.272Z" - }, - { - "x": 4, - "y": 212, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:06.273Z" - }, - { - "x": 5, - "y": 212, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.273Z" - }, - { - "x": 6, - "y": 212, - "type": "TEXT", - "value": "39.328125", - "last_modified": "2023-02-17T00:02:06.273Z" - }, - { - "x": 7, - "y": 212, - "type": "TEXT", - "value": "-82.44182167", - "last_modified": "2023-02-17T00:02:06.273Z" - }, - { - "x": 0, - "y": 213, - "type": "TEXT", - "value": "210", - "last_modified": "2023-02-17T00:02:06.273Z" - }, - { - "x": 1, - "y": 213, - "type": "TEXT", - "value": "22M", - "last_modified": "2023-02-17T00:02:06.273Z" - }, - { - "x": 2, - "y": 213, - "type": "TEXT", - "value": "Pontotoc County", - "last_modified": "2023-02-17T00:02:06.274Z" - }, - { - "x": 3, - "y": 213, - "type": "TEXT", - "value": "Pontotoc", - "last_modified": "2023-02-17T00:02:06.274Z" - }, - { - "x": 4, - "y": 213, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:06.274Z" - }, - { - "x": 5, - "y": 213, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.274Z" - }, - { - "x": 6, - "y": 213, - "type": "TEXT", - "value": "34.27593833", - "last_modified": "2023-02-17T00:02:06.274Z" - }, - { - "x": 7, - "y": 213, - "type": "TEXT", - "value": "-89.03839694", - "last_modified": "2023-02-17T00:02:06.274Z" - }, - { - "x": 0, - "y": 214, - "type": "TEXT", - "value": "211", - "last_modified": "2023-02-17T00:02:06.275Z" - }, - { - "x": 1, - "y": 214, - "type": "TEXT", - "value": "22N", - "last_modified": "2023-02-17T00:02:06.275Z" - }, - { - "x": 2, - "y": 214, - "type": "TEXT", - "value": "Carbon Cty-Jake Arner Memorial", - "last_modified": "2023-02-17T00:02:06.275Z" - }, - { - "x": 3, - "y": 214, - "type": "TEXT", - "value": "Lehighton", - "last_modified": "2023-02-17T00:02:06.275Z" - }, - { - "x": 4, - "y": 214, - "type": "TEXT", - "value": "PA", - "last_modified": "2023-02-17T00:02:06.275Z" - }, - { - "x": 5, - "y": 214, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.275Z" - }, - { - "x": 6, - "y": 214, - "type": "TEXT", - "value": "40.80950889", - "last_modified": "2023-02-17T00:02:06.276Z" - }, - { - "x": 7, - "y": 214, - "type": "TEXT", - "value": "-75.76149639", - "last_modified": "2023-02-17T00:02:06.276Z" - }, - { - "x": 0, - "y": 215, - "type": "TEXT", - "value": "212", - "last_modified": "2023-02-17T00:02:06.276Z" - }, - { - "x": 1, - "y": 215, - "type": "TEXT", - "value": "23J", - "last_modified": "2023-02-17T00:02:06.276Z" - }, - { - "x": 2, - "y": 215, - "type": "TEXT", - "value": "Herlong", - "last_modified": "2023-02-17T00:02:06.276Z" - }, - { - "x": 3, - "y": 215, - "type": "TEXT", - "value": "Jacksonville", - "last_modified": "2023-02-17T00:02:06.276Z" - }, - { - "x": 4, - "y": 215, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:06.277Z" - }, - { - "x": 5, - "y": 215, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.277Z" - }, - { - "x": 6, - "y": 215, - "type": "TEXT", - "value": "30.27778889", - "last_modified": "2023-02-17T00:02:06.277Z" - }, - { - "x": 7, - "y": 215, - "type": "TEXT", - "value": "-81.80594722", - "last_modified": "2023-02-17T00:02:06.277Z" - }, - { - "x": 0, - "y": 216, - "type": "TEXT", - "value": "213", - "last_modified": "2023-02-17T00:02:06.277Z" - }, - { - "x": 1, - "y": 216, - "type": "TEXT", - "value": "23M", - "last_modified": "2023-02-17T00:02:06.277Z" - }, - { - "x": 2, - "y": 216, - "type": "TEXT", - "value": "Clarke County", - "last_modified": "2023-02-17T00:02:06.278Z" - }, - { - "x": 3, - "y": 216, - "type": "TEXT", - "value": "Quitman", - "last_modified": "2023-02-17T00:02:06.278Z" - }, - { - "x": 4, - "y": 216, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:06.278Z" - }, - { - "x": 5, - "y": 216, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.278Z" - }, - { - "x": 6, - "y": 216, - "type": "TEXT", - "value": "32.08487111", - "last_modified": "2023-02-17T00:02:06.278Z" - }, - { - "x": 7, - "y": 216, - "type": "TEXT", - "value": "-88.73893389", - "last_modified": "2023-02-17T00:02:06.278Z" - }, - { - "x": 0, - "y": 217, - "type": "TEXT", - "value": "214", - "last_modified": "2023-02-17T00:02:06.279Z" - }, - { - "x": 1, - "y": 217, - "type": "TEXT", - "value": "23N", - "last_modified": "2023-02-17T00:02:06.279Z" - }, - { - "x": 2, - "y": 217, - "type": "TEXT", - "value": "Bayport Aerodrome", - "last_modified": "2023-02-17T00:02:06.279Z" - }, - { - "x": 3, - "y": 217, - "type": "TEXT", - "value": "Bayport", - "last_modified": "2023-02-17T00:02:06.279Z" - }, - { - "x": 4, - "y": 217, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:06.279Z" - }, - { - "x": 5, - "y": 217, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.279Z" - }, - { - "x": 6, - "y": 217, - "type": "TEXT", - "value": "40.75843139", - "last_modified": "2023-02-17T00:02:06.279Z" - }, - { - "x": 7, - "y": 217, - "type": "TEXT", - "value": "-73.05372083", - "last_modified": "2023-02-17T00:02:06.280Z" - }, - { - "x": 0, - "y": 218, - "type": "TEXT", - "value": "215", - "last_modified": "2023-02-17T00:02:06.280Z" - }, - { - "x": 1, - "y": 218, - "type": "TEXT", - "value": "23R", - "last_modified": "2023-02-17T00:02:06.280Z" - }, - { - "x": 2, - "y": 218, - "type": "TEXT", - "value": "Devine Municipal", - "last_modified": "2023-02-17T00:02:06.280Z" - }, - { - "x": 3, - "y": 218, - "type": "TEXT", - "value": "Devine", - "last_modified": "2023-02-17T00:02:06.280Z" - }, - { - "x": 4, - "y": 218, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:06.280Z" - }, - { - "x": 5, - "y": 218, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.281Z" - }, - { - "x": 6, - "y": 218, - "type": "TEXT", - "value": "29.1384075", - "last_modified": "2023-02-17T00:02:06.281Z" - }, - { - "x": 7, - "y": 218, - "type": "TEXT", - "value": "-98.94189028", - "last_modified": "2023-02-17T00:02:06.281Z" - }, - { - "x": 0, - "y": 219, - "type": "TEXT", - "value": "216", - "last_modified": "2023-02-17T00:02:06.281Z" - }, - { - "x": 1, - "y": 219, - "type": "TEXT", - "value": "24A", - "last_modified": "2023-02-17T00:02:06.281Z" - }, - { - "x": 2, - "y": 219, - "type": "TEXT", - "value": "Jackson County", - "last_modified": "2023-02-17T00:02:06.281Z" - }, - { - "x": 3, - "y": 219, - "type": "TEXT", - "value": "Sylva", - "last_modified": "2023-02-17T00:02:06.281Z" - }, - { - "x": 4, - "y": 219, - "type": "TEXT", - "value": "NC", - "last_modified": "2023-02-17T00:02:06.282Z" - }, - { - "x": 5, - "y": 219, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.282Z" - }, - { - "x": 6, - "y": 219, - "type": "TEXT", - "value": "35.3168625", - "last_modified": "2023-02-17T00:02:06.282Z" - }, - { - "x": 7, - "y": 219, - "type": "TEXT", - "value": "-83.20936806", - "last_modified": "2023-02-17T00:02:06.282Z" - }, - { - "x": 0, - "y": 220, - "type": "TEXT", - "value": "217", - "last_modified": "2023-02-17T00:02:06.282Z" - }, - { - "x": 1, - "y": 220, - "type": "TEXT", - "value": "24J", - "last_modified": "2023-02-17T00:02:06.282Z" - }, - { - "x": 2, - "y": 220, - "type": "TEXT", - "value": "Suwannee County", - "last_modified": "2023-02-17T00:02:06.282Z" - }, - { - "x": 3, - "y": 220, - "type": "TEXT", - "value": "Live Oak", - "last_modified": "2023-02-17T00:02:06.283Z" - }, - { - "x": 4, - "y": 220, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:06.283Z" - }, - { - "x": 5, - "y": 220, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.283Z" - }, - { - "x": 6, - "y": 220, - "type": "TEXT", - "value": "30.30105583", - "last_modified": "2023-02-17T00:02:06.283Z" - }, - { - "x": 7, - "y": 220, - "type": "TEXT", - "value": "-83.02318778", - "last_modified": "2023-02-17T00:02:06.283Z" - }, - { - "x": 0, - "y": 221, - "type": "TEXT", - "value": "218", - "last_modified": "2023-02-17T00:02:06.283Z" - }, - { - "x": 1, - "y": 221, - "type": "TEXT", - "value": "24N", - "last_modified": "2023-02-17T00:02:06.283Z" - }, - { - "x": 2, - "y": 221, - "type": "TEXT", - "value": "Jicarilla Apache Nation", - "last_modified": "2023-02-17T00:02:06.284Z" - }, - { - "x": 3, - "y": 221, - "type": "TEXT", - "value": "Dulce", - "last_modified": "2023-02-17T00:02:06.284Z" - }, - { - "x": 4, - "y": 221, - "type": "TEXT", - "value": "NM", - "last_modified": "2023-02-17T00:02:06.284Z" - }, - { - "x": 5, - "y": 221, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.284Z" - }, - { - "x": 6, - "y": 221, - "type": "TEXT", - "value": "36.828535", - "last_modified": "2023-02-17T00:02:06.284Z" - }, - { - "x": 7, - "y": 221, - "type": "TEXT", - "value": "-106.8841914", - "last_modified": "2023-02-17T00:02:06.284Z" - }, - { - "x": 0, - "y": 222, - "type": "TEXT", - "value": "219", - "last_modified": "2023-02-17T00:02:06.284Z" - }, - { - "x": 1, - "y": 222, - "type": "TEXT", - "value": "25J", - "last_modified": "2023-02-17T00:02:06.284Z" - }, - { - "x": 2, - "y": 222, - "type": "TEXT", - "value": "Cuthbert-Randolph", - "last_modified": "2023-02-17T00:02:06.285Z" - }, - { - "x": 3, - "y": 222, - "type": "TEXT", - "value": "Cuthbert", - "last_modified": "2023-02-17T00:02:06.285Z" - }, - { - "x": 4, - "y": 222, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:06.285Z" - }, - { - "x": 5, - "y": 222, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.285Z" - }, - { - "x": 6, - "y": 222, - "type": "TEXT", - "value": "31.70016583", - "last_modified": "2023-02-17T00:02:06.285Z" - }, - { - "x": 7, - "y": 222, - "type": "TEXT", - "value": "-84.82492194", - "last_modified": "2023-02-17T00:02:06.285Z" - }, - { - "x": 0, - "y": 223, - "type": "TEXT", - "value": "220", - "last_modified": "2023-02-17T00:02:06.285Z" - }, - { - "x": 1, - "y": 223, - "type": "TEXT", - "value": "25M", - "last_modified": "2023-02-17T00:02:06.286Z" - }, - { - "x": 2, - "y": 223, - "type": "TEXT", - "value": "Ripley", - "last_modified": "2023-02-17T00:02:06.286Z" - }, - { - "x": 3, - "y": 223, - "type": "TEXT", - "value": "Ripley", - "last_modified": "2023-02-17T00:02:06.286Z" - }, - { - "x": 4, - "y": 223, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:06.286Z" - }, - { - "x": 5, - "y": 223, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.286Z" - }, - { - "x": 6, - "y": 223, - "type": "TEXT", - "value": "34.72226778", - "last_modified": "2023-02-17T00:02:06.286Z" - }, - { - "x": 7, - "y": 223, - "type": "TEXT", - "value": "-89.01504944", - "last_modified": "2023-02-17T00:02:06.286Z" - }, - { - "x": 0, - "y": 224, - "type": "TEXT", - "value": "221", - "last_modified": "2023-02-17T00:02:06.286Z" - }, - { - "x": 1, - "y": 224, - "type": "TEXT", - "value": "25R", - "last_modified": "2023-02-17T00:02:06.287Z" - }, - { - "x": 2, - "y": 224, - "type": "TEXT", - "value": "International", - "last_modified": "2023-02-17T00:02:06.287Z" - }, - { - "x": 3, - "y": 224, - "type": "TEXT", - "value": "Edinburg", - "last_modified": "2023-02-17T00:02:06.287Z" - }, - { - "x": 4, - "y": 224, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:06.287Z" - }, - { - "x": 5, - "y": 224, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.287Z" - }, - { - "x": 6, - "y": 224, - "type": "TEXT", - "value": "26.44201083", - "last_modified": "2023-02-17T00:02:06.287Z" - }, - { - "x": 7, - "y": 224, - "type": "TEXT", - "value": "-98.12945306", - "last_modified": "2023-02-17T00:02:06.287Z" - }, - { - "x": 0, - "y": 225, - "type": "TEXT", - "value": "222", - "last_modified": "2023-02-17T00:02:06.288Z" - }, - { - "x": 1, - "y": 225, - "type": "TEXT", - "value": "26A", - "last_modified": "2023-02-17T00:02:06.288Z" - }, - { - "x": 2, - "y": 225, - "type": "TEXT", - "value": "Ashland/Lineville", - "last_modified": "2023-02-17T00:02:06.288Z" - }, - { - "x": 3, - "y": 225, - "type": "TEXT", - "value": "Ashland/Lineville", - "last_modified": "2023-02-17T00:02:06.288Z" - }, - { - "x": 4, - "y": 225, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:06.288Z" - }, - { - "x": 5, - "y": 225, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.288Z" - }, - { - "x": 6, - "y": 225, - "type": "TEXT", - "value": "33.28761417", - "last_modified": "2023-02-17T00:02:06.288Z" - }, - { - "x": 7, - "y": 225, - "type": "TEXT", - "value": "-85.80412861", - "last_modified": "2023-02-17T00:02:06.288Z" - }, - { - "x": 0, - "y": 226, - "type": "TEXT", - "value": "223", - "last_modified": "2023-02-17T00:02:06.289Z" - }, - { - "x": 1, - "y": 226, - "type": "TEXT", - "value": "26N", - "last_modified": "2023-02-17T00:02:06.289Z" - }, - { - "x": 2, - "y": 226, - "type": "TEXT", - "value": "Ocean City Muni cipal", - "last_modified": "2023-02-17T00:02:06.289Z" - }, - { - "x": 3, - "y": 226, - "type": "TEXT", - "value": "Ocean City", - "last_modified": "2023-02-17T00:02:06.289Z" - }, - { - "x": 4, - "y": 226, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:06.289Z" - }, - { - "x": 5, - "y": 226, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.289Z" - }, - { - "x": 6, - "y": 226, - "type": "TEXT", - "value": "39.26347222", - "last_modified": "2023-02-17T00:02:06.289Z" - }, - { - "x": 7, - "y": 226, - "type": "TEXT", - "value": "-74.60747222", - "last_modified": "2023-02-17T00:02:06.289Z" - }, - { - "x": 0, - "y": 227, - "type": "TEXT", - "value": "224", - "last_modified": "2023-02-17T00:02:06.289Z" - }, - { - "x": 1, - "y": 227, - "type": "TEXT", - "value": "26R", - "last_modified": "2023-02-17T00:02:06.290Z" - }, - { - "x": 2, - "y": 227, - "type": "TEXT", - "value": "Jackson County", - "last_modified": "2023-02-17T00:02:06.290Z" - }, - { - "x": 3, - "y": 227, - "type": "TEXT", - "value": "Edna/Ganado", - "last_modified": "2023-02-17T00:02:06.290Z" - }, - { - "x": 4, - "y": 227, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:06.290Z" - }, - { - "x": 5, - "y": 227, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.290Z" - }, - { - "x": 6, - "y": 227, - "type": "TEXT", - "value": "29.00101", - "last_modified": "2023-02-17T00:02:06.290Z" - }, - { - "x": 7, - "y": 227, - "type": "TEXT", - "value": "-96.58194667", - "last_modified": "2023-02-17T00:02:06.290Z" - }, - { - "x": 0, - "y": 228, - "type": "TEXT", - "value": "225", - "last_modified": "2023-02-17T00:02:06.290Z" - }, - { - "x": 1, - "y": 228, - "type": "TEXT", - "value": "26U", - "last_modified": "2023-02-17T00:02:06.291Z" - }, - { - "x": 2, - "y": 228, - "type": "TEXT", - "value": "McDermitt State", - "last_modified": "2023-02-17T00:02:06.291Z" - }, - { - "x": 3, - "y": 228, - "type": "TEXT", - "value": "McDermitt", - "last_modified": "2023-02-17T00:02:06.291Z" - }, - { - "x": 4, - "y": 228, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:06.291Z" - }, - { - "x": 5, - "y": 228, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.291Z" - }, - { - "x": 6, - "y": 228, - "type": "TEXT", - "value": "42.00211083", - "last_modified": "2023-02-17T00:02:06.291Z" - }, - { - "x": 7, - "y": 228, - "type": "TEXT", - "value": "-117.7231972", - "last_modified": "2023-02-17T00:02:06.291Z" - }, - { - "x": 0, - "y": 229, - "type": "TEXT", - "value": "226", - "last_modified": "2023-02-17T00:02:06.291Z" - }, - { - "x": 1, - "y": 229, - "type": "TEXT", - "value": "27A", - "last_modified": "2023-02-17T00:02:06.291Z" - }, - { - "x": 2, - "y": 229, - "type": "TEXT", - "value": "Elbert County-Patz", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 3, - "y": 229, - "type": "TEXT", - "value": "Elberton", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 4, - "y": 229, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 5, - "y": 229, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 6, - "y": 229, - "type": "TEXT", - "value": "34.09519722", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 7, - "y": 229, - "type": "TEXT", - "value": "-82.81586417", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 0, - "y": 230, - "type": "TEXT", - "value": "227", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 1, - "y": 230, - "type": "TEXT", - "value": "27D", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 2, - "y": 230, - "type": "TEXT", - "value": "Myers", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 3, - "y": 230, - "type": "TEXT", - "value": "Canby", - "last_modified": "2023-02-17T00:02:06.292Z" - }, - { - "x": 4, - "y": 230, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:06.293Z" - }, - { - "x": 5, - "y": 230, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.293Z" - }, - { - "x": 6, - "y": 230, - "type": "TEXT", - "value": "44.72801889", - "last_modified": "2023-02-17T00:02:06.293Z" - }, - { - "x": 7, - "y": 230, - "type": "TEXT", - "value": "-96.26309972", - "last_modified": "2023-02-17T00:02:06.293Z" - }, - { - "x": 0, - "y": 231, - "type": "TEXT", - "value": "228", - "last_modified": "2023-02-17T00:02:06.293Z" - }, - { - "x": 1, - "y": 231, - "type": "TEXT", - "value": "27J", - "last_modified": "2023-02-17T00:02:06.293Z" - }, - { - "x": 2, - "y": 231, - "type": "TEXT", - "value": "Newberry Municipal", - "last_modified": "2023-02-17T00:02:06.293Z" - }, - { - "x": 3, - "y": 231, - "type": "TEXT", - "value": "Newberry", - "last_modified": "2023-02-17T00:02:06.293Z" - }, - { - "x": 4, - "y": 231, - "type": "TEXT", - "value": "SC", - "last_modified": "2023-02-17T00:02:06.293Z" - }, - { - "x": 5, - "y": 231, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 6, - "y": 231, - "type": "TEXT", - "value": "34.30927778", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 7, - "y": 231, - "type": "TEXT", - "value": "-81.63972222", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 0, - "y": 232, - "type": "TEXT", - "value": "229", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 1, - "y": 232, - "type": "TEXT", - "value": "27K", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 2, - "y": 232, - "type": "TEXT", - "value": "Georgetown-Scott County", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 3, - "y": 232, - "type": "TEXT", - "value": "Georgetown", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 4, - "y": 232, - "type": "TEXT", - "value": "KY", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 5, - "y": 232, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 6, - "y": 232, - "type": "TEXT", - "value": "38.23442528", - "last_modified": "2023-02-17T00:02:06.294Z" - }, - { - "x": 7, - "y": 232, - "type": "TEXT", - "value": "-84.43468667", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 0, - "y": 233, - "type": "TEXT", - "value": "230", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 1, - "y": 233, - "type": "TEXT", - "value": "28J", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 2, - "y": 233, - "type": "TEXT", - "value": "Kay Larkin", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 3, - "y": 233, - "type": "TEXT", - "value": "Palatka", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 4, - "y": 233, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 5, - "y": 233, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 6, - "y": 233, - "type": "TEXT", - "value": "29.65863889", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 7, - "y": 233, - "type": "TEXT", - "value": "-81.68855556", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 0, - "y": 234, - "type": "TEXT", - "value": "231", - "last_modified": "2023-02-17T00:02:06.295Z" - }, - { - "x": 1, - "y": 234, - "type": "TEXT", - "value": "29D", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 2, - "y": 234, - "type": "TEXT", - "value": "Grove City", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 3, - "y": 234, - "type": "TEXT", - "value": "Grove City", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 4, - "y": 234, - "type": "TEXT", - "value": "PA", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 5, - "y": 234, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 6, - "y": 234, - "type": "TEXT", - "value": "41.14597611", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 7, - "y": 234, - "type": "TEXT", - "value": "-80.16592194", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 0, - "y": 235, - "type": "TEXT", - "value": "232", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 1, - "y": 235, - "type": "TEXT", - "value": "29G", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 2, - "y": 235, - "type": "TEXT", - "value": "Portage County", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 3, - "y": 235, - "type": "TEXT", - "value": "Ravenna", - "last_modified": "2023-02-17T00:02:06.296Z" - }, - { - "x": 4, - "y": 235, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 5, - "y": 235, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 6, - "y": 235, - "type": "TEXT", - "value": "41.210195", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 7, - "y": 235, - "type": "TEXT", - "value": "-81.25163083", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 0, - "y": 236, - "type": "TEXT", - "value": "233", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 1, - "y": 236, - "type": "TEXT", - "value": "29S", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 2, - "y": 236, - "type": "TEXT", - "value": "Gardiner", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 3, - "y": 236, - "type": "TEXT", - "value": "Gardiner", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 4, - "y": 236, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 5, - "y": 236, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 6, - "y": 236, - "type": "TEXT", - "value": "45.04993556", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 7, - "y": 236, - "type": "TEXT", - "value": "-110.7466008", - "last_modified": "2023-02-17T00:02:06.297Z" - }, - { - "x": 0, - "y": 237, - "type": "TEXT", - "value": "234", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 1, - "y": 237, - "type": "TEXT", - "value": "2A0", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 2, - "y": 237, - "type": "TEXT", - "value": "Mark Anton", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 3, - "y": 237, - "type": "TEXT", - "value": "Dayton", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 4, - "y": 237, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 5, - "y": 237, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 6, - "y": 237, - "type": "TEXT", - "value": "35.48624611", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 7, - "y": 237, - "type": "TEXT", - "value": "-84.93109722", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 0, - "y": 238, - "type": "TEXT", - "value": "235", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 1, - "y": 238, - "type": "TEXT", - "value": "2A1", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 2, - "y": 238, - "type": "TEXT", - "value": "Jamestown Municipal", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 3, - "y": 238, - "type": "TEXT", - "value": "Jamestown", - "last_modified": "2023-02-17T00:02:06.298Z" - }, - { - "x": 4, - "y": 238, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 5, - "y": 238, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 6, - "y": 238, - "type": "TEXT", - "value": "36.34970833", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 7, - "y": 238, - "type": "TEXT", - "value": "-84.94664472", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 0, - "y": 239, - "type": "TEXT", - "value": "236", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 1, - "y": 239, - "type": "TEXT", - "value": "2A3", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 2, - "y": 239, - "type": "TEXT", - "value": "Larsen Bay", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 3, - "y": 239, - "type": "TEXT", - "value": "Larsen Bay", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 4, - "y": 239, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 5, - "y": 239, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 6, - "y": 239, - "type": "TEXT", - "value": "57.53510667", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 7, - "y": 239, - "type": "TEXT", - "value": "-153.9784169", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 0, - "y": 240, - "type": "TEXT", - "value": "237", - "last_modified": "2023-02-17T00:02:06.299Z" - }, - { - "x": 1, - "y": 240, - "type": "TEXT", - "value": "2A9", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 2, - "y": 240, - "type": "TEXT", - "value": "Kotlik", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 3, - "y": 240, - "type": "TEXT", - "value": "Kotlik", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 4, - "y": 240, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 5, - "y": 240, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 6, - "y": 240, - "type": "TEXT", - "value": "63.03116111", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 7, - "y": 240, - "type": "TEXT", - "value": "-163.5299278", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 0, - "y": 241, - "type": "TEXT", - "value": "238", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 1, - "y": 241, - "type": "TEXT", - "value": "2AK", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 2, - "y": 241, - "type": "TEXT", - "value": "Lime Village", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 3, - "y": 241, - "type": "TEXT", - "value": "Lime Village", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 4, - "y": 241, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 5, - "y": 241, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 6, - "y": 241, - "type": "TEXT", - "value": "61.35848528", - "last_modified": "2023-02-17T00:02:06.300Z" - }, - { - "x": 7, - "y": 241, - "type": "TEXT", - "value": "-155.4403508", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 0, - "y": 242, - "type": "TEXT", - "value": "239", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 1, - "y": 242, - "type": "TEXT", - "value": "2B3", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 2, - "y": 242, - "type": "TEXT", - "value": "Parlin", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 3, - "y": 242, - "type": "TEXT", - "value": "Newport", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 4, - "y": 242, - "type": "TEXT", - "value": "NH", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 5, - "y": 242, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 6, - "y": 242, - "type": "TEXT", - "value": "43.38812944", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 7, - "y": 242, - "type": "TEXT", - "value": "-72.18925417", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 0, - "y": 243, - "type": "TEXT", - "value": "240", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 1, - "y": 243, - "type": "TEXT", - "value": "2B7", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 2, - "y": 243, - "type": "TEXT", - "value": "Pittsfield Municipal", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 3, - "y": 243, - "type": "TEXT", - "value": "Pittsfield", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 4, - "y": 243, - "type": "TEXT", - "value": "ME", - "last_modified": "2023-02-17T00:02:06.301Z" - }, - { - "x": 5, - "y": 243, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 6, - "y": 243, - "type": "TEXT", - "value": "44.76852778", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 7, - "y": 243, - "type": "TEXT", - "value": "-69.37441667", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 0, - "y": 244, - "type": "TEXT", - "value": "241", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 1, - "y": 244, - "type": "TEXT", - "value": "2B9", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 2, - "y": 244, - "type": "TEXT", - "value": "Post Mills", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 3, - "y": 244, - "type": "TEXT", - "value": "Post Mills", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 4, - "y": 244, - "type": "TEXT", - "value": "VT", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 5, - "y": 244, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 6, - "y": 244, - "type": "TEXT", - "value": "43.884235", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 7, - "y": 244, - "type": "TEXT", - "value": "-72.25370333", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 0, - "y": 245, - "type": "TEXT", - "value": "242", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 1, - "y": 245, - "type": "TEXT", - "value": "2D1", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 2, - "y": 245, - "type": "TEXT", - "value": "Barber", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 3, - "y": 245, - "type": "TEXT", - "value": "Alliance", - "last_modified": "2023-02-17T00:02:06.302Z" - }, - { - "x": 4, - "y": 245, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 5, - "y": 245, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 6, - "y": 245, - "type": "TEXT", - "value": "40.97089139", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 7, - "y": 245, - "type": "TEXT", - "value": "-81.09981889", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 0, - "y": 246, - "type": "TEXT", - "value": "243", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 1, - "y": 246, - "type": "TEXT", - "value": "2D5", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 2, - "y": 246, - "type": "TEXT", - "value": "Oakes Municipal", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 3, - "y": 246, - "type": "TEXT", - "value": "Oakes", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 4, - "y": 246, - "type": "TEXT", - "value": "ND", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 5, - "y": 246, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 6, - "y": 246, - "type": "TEXT", - "value": "46.17301972", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 7, - "y": 246, - "type": "TEXT", - "value": "-98.07987556", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 0, - "y": 247, - "type": "TEXT", - "value": "244", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 1, - "y": 247, - "type": "TEXT", - "value": "2F5", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 2, - "y": 247, - "type": "TEXT", - "value": "Lamesa Municipal", - "last_modified": "2023-02-17T00:02:06.303Z" - }, - { - "x": 3, - "y": 247, - "type": "TEXT", - "value": "Lamesa", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 4, - "y": 247, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 5, - "y": 247, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 6, - "y": 247, - "type": "TEXT", - "value": "32.75627778", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 7, - "y": 247, - "type": "TEXT", - "value": "-101.9194722", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 0, - "y": 248, - "type": "TEXT", - "value": "245", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 1, - "y": 248, - "type": "TEXT", - "value": "2F6", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 2, - "y": 248, - "type": "TEXT", - "value": "Skiatook Municipal", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 3, - "y": 248, - "type": "TEXT", - "value": "Skiatook", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 4, - "y": 248, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 5, - "y": 248, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 6, - "y": 248, - "type": "TEXT", - "value": "36.357035", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 7, - "y": 248, - "type": "TEXT", - "value": "-96.01138556", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 0, - "y": 249, - "type": "TEXT", - "value": "246", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 1, - "y": 249, - "type": "TEXT", - "value": "2F7", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 2, - "y": 249, - "type": "TEXT", - "value": "Commerce Municipal", - "last_modified": "2023-02-17T00:02:06.304Z" - }, - { - "x": 3, - "y": 249, - "type": "TEXT", - "value": "Commerce", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 4, - "y": 249, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 5, - "y": 249, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 6, - "y": 249, - "type": "TEXT", - "value": "33.29288889", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 7, - "y": 249, - "type": "TEXT", - "value": "-95.89641806", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 0, - "y": 250, - "type": "TEXT", - "value": "247", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 1, - "y": 250, - "type": "TEXT", - "value": "2F8", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 2, - "y": 250, - "type": "TEXT", - "value": "Morehouse Memorial", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 3, - "y": 250, - "type": "TEXT", - "value": "Bastrop", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 4, - "y": 250, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 5, - "y": 250, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 6, - "y": 250, - "type": "TEXT", - "value": "32.75607944", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 7, - "y": 250, - "type": "TEXT", - "value": "-91.88057194", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 0, - "y": 251, - "type": "TEXT", - "value": "248", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 1, - "y": 251, - "type": "TEXT", - "value": "2G2", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 2, - "y": 251, - "type": "TEXT", - "value": "Jefferson County Airpark", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 3, - "y": 251, - "type": "TEXT", - "value": "Steubenville", - "last_modified": "2023-02-17T00:02:06.305Z" - }, - { - "x": 4, - "y": 251, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 5, - "y": 251, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 6, - "y": 251, - "type": "TEXT", - "value": "40.35944306", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 7, - "y": 251, - "type": "TEXT", - "value": "-80.70007806", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 0, - "y": 252, - "type": "TEXT", - "value": "249", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 1, - "y": 252, - "type": "TEXT", - "value": "2G3", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 2, - "y": 252, - "type": "TEXT", - "value": "Connellsville", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 3, - "y": 252, - "type": "TEXT", - "value": "Connellsville", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 4, - "y": 252, - "type": "TEXT", - "value": "PA", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 5, - "y": 252, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 6, - "y": 252, - "type": "TEXT", - "value": "39.95893667", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 7, - "y": 252, - "type": "TEXT", - "value": "-79.65713306", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 0, - "y": 253, - "type": "TEXT", - "value": "250", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 1, - "y": 253, - "type": "TEXT", - "value": "2G4", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 2, - "y": 253, - "type": "TEXT", - "value": "Garrett County", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 3, - "y": 253, - "type": "TEXT", - "value": "Oakland", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 4, - "y": 253, - "type": "TEXT", - "value": "MD", - "last_modified": "2023-02-17T00:02:06.306Z" - }, - { - "x": 5, - "y": 253, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:06.307Z" - }, - { - "x": 6, - "y": 253, - "type": "TEXT", - "value": "39.58027778", - "last_modified": "2023-02-17T00:02:06.307Z" - }, - { - "x": 7, - "y": 253, - "type": "TEXT", - "value": "-79.33941667", - "last_modified": "2023-02-17T00:02:06.307Z" - }, - { - "x": 12, - "y": 17, - "type": "COMPUTED", - "value": "138", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 17, - "type": "COMPUTED", - "value": "1B1", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 17, - "type": "COMPUTED", - "value": "Columbia Cty", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 17, - "type": "COMPUTED", - "value": "Hudson", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 17, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 17, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 17, - "type": "COMPUTED", - "value": "42.29130028", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 17, - "type": "COMPUTED", - "value": "-73.71031944", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 18, - "type": "COMPUTED", - "value": "156", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 18, - "type": "COMPUTED", - "value": "1G6", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 18, - "type": "COMPUTED", - "value": "Michael", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 18, - "type": "COMPUTED", - "value": "Cicero", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 18, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 18, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 18, - "type": "COMPUTED", - "value": "43.18166667", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 18, - "type": "COMPUTED", - "value": "-76.12777778", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 19, - "type": "COMPUTED", - "value": "161", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 19, - "type": "COMPUTED", - "value": "1I5", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 19, - "type": "COMPUTED", - "value": "Freehold", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 19, - "type": "COMPUTED", - "value": "Freehold", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 19, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 19, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 19, - "type": "COMPUTED", - "value": "42.36425", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 19, - "type": "COMPUTED", - "value": "-74.06596806", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 20, - "type": "COMPUTED", - "value": "178", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 20, - "type": "COMPUTED", - "value": "1N2", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 20, - "type": "COMPUTED", - "value": "Spadaro", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 20, - "type": "COMPUTED", - "value": "East Moriches", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 20, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 20, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 20, - "type": "COMPUTED", - "value": "40.82787639", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 20, - "type": "COMPUTED", - "value": "-72.74871083", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 21, - "type": "COMPUTED", - "value": "203", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 21, - "type": "COMPUTED", - "value": "20N", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 21, - "type": "COMPUTED", - "value": "Kingston-Ulster", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 21, - "type": "COMPUTED", - "value": "Kingston", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 21, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 21, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 21, - "type": "COMPUTED", - "value": "41.9852525", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 21, - "type": "COMPUTED", - "value": "-73.96409722", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 22, - "type": "COMPUTED", - "value": "214", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 22, - "type": "COMPUTED", - "value": "23N", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 22, - "type": "COMPUTED", - "value": "Bayport Aerodrome", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 22, - "type": "COMPUTED", - "value": "Bayport", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 22, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 22, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 22, - "type": "COMPUTED", - "value": "40.75843139", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 22, - "type": "COMPUTED", - "value": "-73.05372083", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 0, - "y": 254, - "type": "TEXT", - "value": "251", - "last_modified": "2023-02-17T00:02:52.294Z" - }, - { - "x": 1, - "y": 254, - "type": "TEXT", - "value": "2G9", - "last_modified": "2023-02-17T00:02:52.300Z" - }, - { - "x": 2, - "y": 254, - "type": "TEXT", - "value": "Somerset County", - "last_modified": "2023-02-17T00:02:52.304Z" - }, - { - "x": 3, - "y": 254, - "type": "TEXT", - "value": "Somerset", - "last_modified": "2023-02-17T00:02:52.309Z" - }, - { - "x": 4, - "y": 254, - "type": "TEXT", - "value": "PA", - "last_modified": "2023-02-17T00:02:52.313Z" - }, - { - "x": 5, - "y": 254, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.318Z" - }, - { - "x": 6, - "y": 254, - "type": "TEXT", - "value": "40.03911111", - "last_modified": "2023-02-17T00:02:52.322Z" - }, - { - "x": 7, - "y": 254, - "type": "TEXT", - "value": "-79.01455556", - "last_modified": "2023-02-17T00:02:52.326Z" - }, - { - "x": 0, - "y": 255, - "type": "TEXT", - "value": "252", - "last_modified": "2023-02-17T00:02:52.330Z" - }, - { - "x": 1, - "y": 255, - "type": "TEXT", - "value": "2H0", - "last_modified": "2023-02-17T00:02:52.334Z" - }, - { - "x": 2, - "y": 255, - "type": "TEXT", - "value": "Shelby County", - "last_modified": "2023-02-17T00:02:52.338Z" - }, - { - "x": 3, - "y": 255, - "type": "TEXT", - "value": "Shelbyville", - "last_modified": "2023-02-17T00:02:52.342Z" - }, - { - "x": 4, - "y": 255, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:52.346Z" - }, - { - "x": 5, - "y": 255, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.350Z" - }, - { - "x": 6, - "y": 255, - "type": "TEXT", - "value": "39.41042861", - "last_modified": "2023-02-17T00:02:52.354Z" - }, - { - "x": 7, - "y": 255, - "type": "TEXT", - "value": "-88.8454325", - "last_modified": "2023-02-17T00:02:52.358Z" - }, - { - "x": 0, - "y": 256, - "type": "TEXT", - "value": "253", - "last_modified": "2023-02-17T00:02:52.363Z" - }, - { - "x": 1, - "y": 256, - "type": "TEXT", - "value": "2H2", - "last_modified": "2023-02-17T00:02:52.367Z" - }, - { - "x": 2, - "y": 256, - "type": "TEXT", - "value": "Aurora Memorial Municipal", - "last_modified": "2023-02-17T00:02:52.371Z" - }, - { - "x": 3, - "y": 256, - "type": "TEXT", - "value": "Aurora", - "last_modified": "2023-02-17T00:02:52.375Z" - }, - { - "x": 4, - "y": 256, - "type": "TEXT", - "value": "MO", - "last_modified": "2023-02-17T00:02:52.379Z" - }, - { - "x": 5, - "y": 256, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.383Z" - }, - { - "x": 6, - "y": 256, - "type": "TEXT", - "value": "36.96230778", - "last_modified": "2023-02-17T00:02:52.387Z" - }, - { - "x": 7, - "y": 256, - "type": "TEXT", - "value": "-93.69531111", - "last_modified": "2023-02-17T00:02:52.391Z" - }, - { - "x": 0, - "y": 257, - "type": "TEXT", - "value": "254", - "last_modified": "2023-02-17T00:02:52.395Z" - }, - { - "x": 1, - "y": 257, - "type": "TEXT", - "value": "2I0", - "last_modified": "2023-02-17T00:02:52.399Z" - }, - { - "x": 2, - "y": 257, - "type": "TEXT", - "value": "Madisonville Municipal", - "last_modified": "2023-02-17T00:02:52.403Z" - }, - { - "x": 3, - "y": 257, - "type": "TEXT", - "value": "Madisonville", - "last_modified": "2023-02-17T00:02:52.407Z" - }, - { - "x": 4, - "y": 257, - "type": "TEXT", - "value": "KY", - "last_modified": "2023-02-17T00:02:52.411Z" - }, - { - "x": 5, - "y": 257, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.415Z" - }, - { - "x": 6, - "y": 257, - "type": "TEXT", - "value": "37.35502778", - "last_modified": "2023-02-17T00:02:52.419Z" - }, - { - "x": 7, - "y": 257, - "type": "TEXT", - "value": "-87.39963889", - "last_modified": "2023-02-17T00:02:52.423Z" - }, - { - "x": 0, - "y": 258, - "type": "TEXT", - "value": "255", - "last_modified": "2023-02-17T00:02:52.427Z" - }, - { - "x": 1, - "y": 258, - "type": "TEXT", - "value": "2I5", - "last_modified": "2023-02-17T00:02:52.431Z" - }, - { - "x": 2, - "y": 258, - "type": "TEXT", - "value": "Chanute", - "last_modified": "2023-02-17T00:02:52.435Z" - }, - { - "x": 3, - "y": 258, - "type": "TEXT", - "value": "Rantoul", - "last_modified": "2023-02-17T00:02:52.438Z" - }, - { - "x": 4, - "y": 258, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:52.442Z" - }, - { - "x": 5, - "y": 258, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.446Z" - }, - { - "x": 6, - "y": 258, - "type": "TEXT", - "value": "40.29355556", - "last_modified": "2023-02-17T00:02:52.450Z" - }, - { - "x": 7, - "y": 258, - "type": "TEXT", - "value": "-88.14236111", - "last_modified": "2023-02-17T00:02:52.454Z" - }, - { - "x": 0, - "y": 259, - "type": "TEXT", - "value": "256", - "last_modified": "2023-02-17T00:02:52.457Z" - }, - { - "x": 1, - "y": 259, - "type": "TEXT", - "value": "2IS", - "last_modified": "2023-02-17T00:02:52.461Z" - }, - { - "x": 2, - "y": 259, - "type": "TEXT", - "value": "Airglades", - "last_modified": "2023-02-17T00:02:52.465Z" - }, - { - "x": 3, - "y": 259, - "type": "TEXT", - "value": "Clewiston", - "last_modified": "2023-02-17T00:02:52.469Z" - }, - { - "x": 4, - "y": 259, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:52.473Z" - }, - { - "x": 5, - "y": 259, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.477Z" - }, - { - "x": 6, - "y": 259, - "type": "TEXT", - "value": "26.74200972", - "last_modified": "2023-02-17T00:02:52.480Z" - }, - { - "x": 7, - "y": 259, - "type": "TEXT", - "value": "-81.04978917", - "last_modified": "2023-02-17T00:02:52.484Z" - }, - { - "x": 0, - "y": 260, - "type": "TEXT", - "value": "257", - "last_modified": "2023-02-17T00:02:52.488Z" - }, - { - "x": 1, - "y": 260, - "type": "TEXT", - "value": "2J2", - "last_modified": "2023-02-17T00:02:52.492Z" - }, - { - "x": 2, - "y": 260, - "type": "TEXT", - "value": "Liberty County", - "last_modified": "2023-02-17T00:02:52.496Z" - }, - { - "x": 3, - "y": 260, - "type": "TEXT", - "value": "Hinesville", - "last_modified": "2023-02-17T00:02:52.499Z" - }, - { - "x": 4, - "y": 260, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:52.503Z" - }, - { - "x": 5, - "y": 260, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.507Z" - }, - { - "x": 6, - "y": 260, - "type": "TEXT", - "value": "31.78461111", - "last_modified": "2023-02-17T00:02:52.511Z" - }, - { - "x": 7, - "y": 260, - "type": "TEXT", - "value": "-81.64116667", - "last_modified": "2023-02-17T00:02:52.515Z" - }, - { - "x": 0, - "y": 261, - "type": "TEXT", - "value": "258", - "last_modified": "2023-02-17T00:02:52.518Z" - }, - { - "x": 1, - "y": 261, - "type": "TEXT", - "value": "2J3", - "last_modified": "2023-02-17T00:02:52.522Z" - }, - { - "x": 2, - "y": 261, - "type": "TEXT", - "value": "Louisville Municipal", - "last_modified": "2023-02-17T00:02:52.526Z" - }, - { - "x": 3, - "y": 261, - "type": "TEXT", - "value": "Louisville", - "last_modified": "2023-02-17T00:02:52.530Z" - }, - { - "x": 4, - "y": 261, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:52.533Z" - }, - { - "x": 5, - "y": 261, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.537Z" - }, - { - "x": 6, - "y": 261, - "type": "TEXT", - "value": "32.98654083", - "last_modified": "2023-02-17T00:02:52.541Z" - }, - { - "x": 7, - "y": 261, - "type": "TEXT", - "value": "-82.38568139", - "last_modified": "2023-02-17T00:02:52.545Z" - }, - { - "x": 0, - "y": 262, - "type": "TEXT", - "value": "259", - "last_modified": "2023-02-17T00:02:52.548Z" - }, - { - "x": 1, - "y": 262, - "type": "TEXT", - "value": "2J5", - "last_modified": "2023-02-17T00:02:52.552Z" - }, - { - "x": 2, - "y": 262, - "type": "TEXT", - "value": "Millen", - "last_modified": "2023-02-17T00:02:52.556Z" - }, - { - "x": 3, - "y": 262, - "type": "TEXT", - "value": "Millen", - "last_modified": "2023-02-17T00:02:52.560Z" - }, - { - "x": 4, - "y": 262, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:52.563Z" - }, - { - "x": 5, - "y": 262, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.567Z" - }, - { - "x": 6, - "y": 262, - "type": "TEXT", - "value": "32.89376972", - "last_modified": "2023-02-17T00:02:52.571Z" - }, - { - "x": 7, - "y": 262, - "type": "TEXT", - "value": "-81.96511583", - "last_modified": "2023-02-17T00:02:52.574Z" - }, - { - "x": 0, - "y": 263, - "type": "TEXT", - "value": "260", - "last_modified": "2023-02-17T00:02:52.578Z" - }, - { - "x": 1, - "y": 263, - "type": "TEXT", - "value": "2J9", - "last_modified": "2023-02-17T00:02:52.582Z" - }, - { - "x": 2, - "y": 263, - "type": "TEXT", - "value": "Quincy Municipal", - "last_modified": "2023-02-17T00:02:52.586Z" - }, - { - "x": 3, - "y": 263, - "type": "TEXT", - "value": "Quincy", - "last_modified": "2023-02-17T00:02:52.589Z" - }, - { - "x": 4, - "y": 263, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:52.593Z" - }, - { - "x": 5, - "y": 263, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.597Z" - }, - { - "x": 6, - "y": 263, - "type": "TEXT", - "value": "30.59786111", - "last_modified": "2023-02-17T00:02:52.600Z" - }, - { - "x": 7, - "y": 263, - "type": "TEXT", - "value": "-84.55741667", - "last_modified": "2023-02-17T00:02:52.604Z" - }, - { - "x": 0, - "y": 264, - "type": "TEXT", - "value": "261", - "last_modified": "2023-02-17T00:02:52.608Z" - }, - { - "x": 1, - "y": 264, - "type": "TEXT", - "value": "2K3", - "last_modified": "2023-02-17T00:02:52.611Z" - }, - { - "x": 2, - "y": 264, - "type": "TEXT", - "value": "Stanton County Municipal", - "last_modified": "2023-02-17T00:02:52.615Z" - }, - { - "x": 3, - "y": 264, - "type": "TEXT", - "value": "Johnson", - "last_modified": "2023-02-17T00:02:52.619Z" - }, - { - "x": 4, - "y": 264, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:52.622Z" - }, - { - "x": 5, - "y": 264, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.626Z" - }, - { - "x": 6, - "y": 264, - "type": "TEXT", - "value": "37.58271111", - "last_modified": "2023-02-17T00:02:52.630Z" - }, - { - "x": 7, - "y": 264, - "type": "TEXT", - "value": "-101.73281", - "last_modified": "2023-02-17T00:02:52.634Z" - }, - { - "x": 0, - "y": 265, - "type": "TEXT", - "value": "262", - "last_modified": "2023-02-17T00:02:52.638Z" - }, - { - "x": 1, - "y": 265, - "type": "TEXT", - "value": "2K4", - "last_modified": "2023-02-17T00:02:52.641Z" - }, - { - "x": 2, - "y": 265, - "type": "TEXT", - "value": "Scott", - "last_modified": "2023-02-17T00:02:52.645Z" - }, - { - "x": 3, - "y": 265, - "type": "TEXT", - "value": "Mangum", - "last_modified": "2023-02-17T00:02:52.649Z" - }, - { - "x": 4, - "y": 265, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:52.652Z" - }, - { - "x": 5, - "y": 265, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.656Z" - }, - { - "x": 6, - "y": 265, - "type": "TEXT", - "value": "34.89172583", - "last_modified": "2023-02-17T00:02:52.660Z" - }, - { - "x": 7, - "y": 265, - "type": "TEXT", - "value": "-99.52675667", - "last_modified": "2023-02-17T00:02:52.663Z" - }, - { - "x": 0, - "y": 266, - "type": "TEXT", - "value": "263", - "last_modified": "2023-02-17T00:02:52.667Z" - }, - { - "x": 1, - "y": 266, - "type": "TEXT", - "value": "2K5", - "last_modified": "2023-02-17T00:02:52.670Z" - }, - { - "x": 2, - "y": 266, - "type": "TEXT", - "value": "Telida", - "last_modified": "2023-02-17T00:02:52.674Z" - }, - { - "x": 3, - "y": 266, - "type": "TEXT", - "value": "Telida", - "last_modified": "2023-02-17T00:02:52.678Z" - }, - { - "x": 4, - "y": 266, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:52.681Z" - }, - { - "x": 5, - "y": 266, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.685Z" - }, - { - "x": 6, - "y": 266, - "type": "TEXT", - "value": "63.39387278", - "last_modified": "2023-02-17T00:02:52.688Z" - }, - { - "x": 7, - "y": 266, - "type": "TEXT", - "value": "-153.2689733", - "last_modified": "2023-02-17T00:02:52.692Z" - }, - { - "x": 0, - "y": 267, - "type": "TEXT", - "value": "264", - "last_modified": "2023-02-17T00:02:52.696Z" - }, - { - "x": 1, - "y": 267, - "type": "TEXT", - "value": "2M0", - "last_modified": "2023-02-17T00:02:52.699Z" - }, - { - "x": 2, - "y": 267, - "type": "TEXT", - "value": "Princeton-Caldwell County", - "last_modified": "2023-02-17T00:02:52.703Z" - }, - { - "x": 3, - "y": 267, - "type": "TEXT", - "value": "Princeton", - "last_modified": "2023-02-17T00:02:52.706Z" - }, - { - "x": 4, - "y": 267, - "type": "TEXT", - "value": "KY", - "last_modified": "2023-02-17T00:02:52.710Z" - }, - { - "x": 5, - "y": 267, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.714Z" - }, - { - "x": 6, - "y": 267, - "type": "TEXT", - "value": "37.11560444", - "last_modified": "2023-02-17T00:02:52.717Z" - }, - { - "x": 7, - "y": 267, - "type": "TEXT", - "value": "-87.85556944", - "last_modified": "2023-02-17T00:02:52.721Z" - }, - { - "x": 0, - "y": 268, - "type": "TEXT", - "value": "265", - "last_modified": "2023-02-17T00:02:52.724Z" - }, - { - "x": 1, - "y": 268, - "type": "TEXT", - "value": "2M2", - "last_modified": "2023-02-17T00:02:52.728Z" - }, - { - "x": 2, - "y": 268, - "type": "TEXT", - "value": "Lawrenceburg Municipal", - "last_modified": "2023-02-17T00:02:52.732Z" - }, - { - "x": 3, - "y": 268, - "type": "TEXT", - "value": "Lawrenceburg", - "last_modified": "2023-02-17T00:02:52.735Z" - }, - { - "x": 4, - "y": 268, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:52.739Z" - }, - { - "x": 5, - "y": 268, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.742Z" - }, - { - "x": 6, - "y": 268, - "type": "TEXT", - "value": "35.2343025", - "last_modified": "2023-02-17T00:02:52.746Z" - }, - { - "x": 7, - "y": 268, - "type": "TEXT", - "value": "-87.25793222", - "last_modified": "2023-02-17T00:02:52.749Z" - }, - { - "x": 0, - "y": 269, - "type": "TEXT", - "value": "266", - "last_modified": "2023-02-17T00:02:52.753Z" - }, - { - "x": 1, - "y": 269, - "type": "TEXT", - "value": "2M3", - "last_modified": "2023-02-17T00:02:52.756Z" - }, - { - "x": 2, - "y": 269, - "type": "TEXT", - "value": "Sallisaw Municipal", - "last_modified": "2023-02-17T00:02:52.760Z" - }, - { - "x": 3, - "y": 269, - "type": "TEXT", - "value": "Sallisaw", - "last_modified": "2023-02-17T00:02:52.763Z" - }, - { - "x": 4, - "y": 269, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:52.767Z" - }, - { - "x": 5, - "y": 269, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.770Z" - }, - { - "x": 6, - "y": 269, - "type": "TEXT", - "value": "35.43816667", - "last_modified": "2023-02-17T00:02:52.774Z" - }, - { - "x": 7, - "y": 269, - "type": "TEXT", - "value": "-94.80277778", - "last_modified": "2023-02-17T00:02:52.778Z" - }, - { - "x": 0, - "y": 270, - "type": "TEXT", - "value": "267", - "last_modified": "2023-02-17T00:02:52.781Z" - }, - { - "x": 1, - "y": 270, - "type": "TEXT", - "value": "2M4", - "last_modified": "2023-02-17T00:02:52.785Z" - }, - { - "x": 2, - "y": 270, - "type": "TEXT", - "value": "G. V. Montgomery", - "last_modified": "2023-02-17T00:02:52.788Z" - }, - { - "x": 3, - "y": 270, - "type": "TEXT", - "value": "Forest", - "last_modified": "2023-02-17T00:02:52.792Z" - }, - { - "x": 4, - "y": 270, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:52.795Z" - }, - { - "x": 5, - "y": 270, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.799Z" - }, - { - "x": 6, - "y": 270, - "type": "TEXT", - "value": "32.35347778", - "last_modified": "2023-02-17T00:02:52.802Z" - }, - { - "x": 7, - "y": 270, - "type": "TEXT", - "value": "-89.48867944", - "last_modified": "2023-02-17T00:02:52.806Z" - }, - { - "x": 0, - "y": 271, - "type": "TEXT", - "value": "268", - "last_modified": "2023-02-17T00:02:52.809Z" - }, - { - "x": 1, - "y": 271, - "type": "TEXT", - "value": "2M8", - "last_modified": "2023-02-17T00:02:52.813Z" - }, - { - "x": 2, - "y": 271, - "type": "TEXT", - "value": "Charles W. Baker", - "last_modified": "2023-02-17T00:02:52.816Z" - }, - { - "x": 3, - "y": 271, - "type": "TEXT", - "value": "Millington", - "last_modified": "2023-02-17T00:02:52.820Z" - }, - { - "x": 4, - "y": 271, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:52.823Z" - }, - { - "x": 5, - "y": 271, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.826Z" - }, - { - "x": 6, - "y": 271, - "type": "TEXT", - "value": "35.27897583", - "last_modified": "2023-02-17T00:02:52.830Z" - }, - { - "x": 7, - "y": 271, - "type": "TEXT", - "value": "-89.93147611", - "last_modified": "2023-02-17T00:02:52.833Z" - }, - { - "x": 0, - "y": 272, - "type": "TEXT", - "value": "269", - "last_modified": "2023-02-17T00:02:52.837Z" - }, - { - "x": 1, - "y": 272, - "type": "TEXT", - "value": "2O1", - "last_modified": "2023-02-17T00:02:52.840Z" - }, - { - "x": 2, - "y": 272, - "type": "TEXT", - "value": "Gansner", - "last_modified": "2023-02-17T00:02:52.844Z" - }, - { - "x": 3, - "y": 272, - "type": "TEXT", - "value": "Quincy", - "last_modified": "2023-02-17T00:02:52.847Z" - }, - { - "x": 4, - "y": 272, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:52.851Z" - }, - { - "x": 5, - "y": 272, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.854Z" - }, - { - "x": 6, - "y": 272, - "type": "TEXT", - "value": "39.94378056", - "last_modified": "2023-02-17T00:02:52.858Z" - }, - { - "x": 7, - "y": 272, - "type": "TEXT", - "value": "-120.9468983", - "last_modified": "2023-02-17T00:02:52.861Z" - }, - { - "x": 0, - "y": 273, - "type": "TEXT", - "value": "270", - "last_modified": "2023-02-17T00:02:52.865Z" - }, - { - "x": 1, - "y": 273, - "type": "TEXT", - "value": "2O3", - "last_modified": "2023-02-17T00:02:52.868Z" - }, - { - "x": 2, - "y": 273, - "type": "TEXT", - "value": "Angwin-Parrett", - "last_modified": "2023-02-17T00:02:52.871Z" - }, - { - "x": 3, - "y": 273, - "type": "TEXT", - "value": "Angwin", - "last_modified": "2023-02-17T00:02:52.875Z" - }, - { - "x": 4, - "y": 273, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:52.878Z" - }, - { - "x": 5, - "y": 273, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.882Z" - }, - { - "x": 6, - "y": 273, - "type": "TEXT", - "value": "38.57851778", - "last_modified": "2023-02-17T00:02:52.885Z" - }, - { - "x": 7, - "y": 273, - "type": "TEXT", - "value": "-122.4352572", - "last_modified": "2023-02-17T00:02:52.888Z" - }, - { - "x": 0, - "y": 274, - "type": "TEXT", - "value": "271", - "last_modified": "2023-02-17T00:02:52.892Z" - }, - { - "x": 1, - "y": 274, - "type": "TEXT", - "value": "2O6", - "last_modified": "2023-02-17T00:02:52.896Z" - }, - { - "x": 2, - "y": 274, - "type": "TEXT", - "value": "Chowchilla", - "last_modified": "2023-02-17T00:02:52.899Z" - }, - { - "x": 3, - "y": 274, - "type": "TEXT", - "value": "Chowchilla", - "last_modified": "2023-02-17T00:02:52.903Z" - }, - { - "x": 4, - "y": 274, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:52.906Z" - }, - { - "x": 5, - "y": 274, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.910Z" - }, - { - "x": 6, - "y": 274, - "type": "TEXT", - "value": "37.11244417", - "last_modified": "2023-02-17T00:02:52.913Z" - }, - { - "x": 7, - "y": 274, - "type": "TEXT", - "value": "-120.2468406", - "last_modified": "2023-02-17T00:02:52.916Z" - }, - { - "x": 0, - "y": 275, - "type": "TEXT", - "value": "272", - "last_modified": "2023-02-17T00:02:52.920Z" - }, - { - "x": 1, - "y": 275, - "type": "TEXT", - "value": "2O7", - "last_modified": "2023-02-17T00:02:52.923Z" - }, - { - "x": 2, - "y": 275, - "type": "TEXT", - "value": "Independence", - "last_modified": "2023-02-17T00:02:52.927Z" - }, - { - "x": 3, - "y": 275, - "type": "TEXT", - "value": "Independence", - "last_modified": "2023-02-17T00:02:52.930Z" - }, - { - "x": 4, - "y": 275, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:52.934Z" - }, - { - "x": 5, - "y": 275, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.938Z" - }, - { - "x": 6, - "y": 275, - "type": "TEXT", - "value": "36.81382111", - "last_modified": "2023-02-17T00:02:52.941Z" - }, - { - "x": 7, - "y": 275, - "type": "TEXT", - "value": "-118.2050956", - "last_modified": "2023-02-17T00:02:52.945Z" - }, - { - "x": 0, - "y": 276, - "type": "TEXT", - "value": "273", - "last_modified": "2023-02-17T00:02:52.949Z" - }, - { - "x": 1, - "y": 276, - "type": "TEXT", - "value": "2O8", - "last_modified": "2023-02-17T00:02:52.952Z" - }, - { - "x": 2, - "y": 276, - "type": "TEXT", - "value": "Hinton Municipal", - "last_modified": "2023-02-17T00:02:52.956Z" - }, - { - "x": 3, - "y": 276, - "type": "TEXT", - "value": "Hinton", - "last_modified": "2023-02-17T00:02:52.960Z" - }, - { - "x": 4, - "y": 276, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:52.964Z" - }, - { - "x": 5, - "y": 276, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:52.967Z" - }, - { - "x": 6, - "y": 276, - "type": "TEXT", - "value": "35.50592472", - "last_modified": "2023-02-17T00:02:52.979Z" - }, - { - "x": 7, - "y": 276, - "type": "TEXT", - "value": "-98.34236111", - "last_modified": "2023-02-17T00:02:52.996Z" - }, - { - "x": 0, - "y": 277, - "type": "TEXT", - "value": "274", - "last_modified": "2023-02-17T00:02:53.001Z" - }, - { - "x": 1, - "y": 277, - "type": "TEXT", - "value": "2P2", - "last_modified": "2023-02-17T00:02:53.006Z" - }, - { - "x": 2, - "y": 277, - "type": "TEXT", - "value": "Washington Island", - "last_modified": "2023-02-17T00:02:53.013Z" - }, - { - "x": 3, - "y": 277, - "type": "TEXT", - "value": "Washington Island", - "last_modified": "2023-02-17T00:02:53.016Z" - }, - { - "x": 4, - "y": 277, - "type": "TEXT", - "value": "WI", - "last_modified": "2023-02-17T00:02:53.020Z" - }, - { - "x": 5, - "y": 277, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.023Z" - }, - { - "x": 6, - "y": 277, - "type": "TEXT", - "value": "45.38620833", - "last_modified": "2023-02-17T00:02:53.027Z" - }, - { - "x": 7, - "y": 277, - "type": "TEXT", - "value": "-86.92448056", - "last_modified": "2023-02-17T00:02:53.030Z" - }, - { - "x": 0, - "y": 278, - "type": "TEXT", - "value": "275", - "last_modified": "2023-02-17T00:02:53.033Z" - }, - { - "x": 1, - "y": 278, - "type": "TEXT", - "value": "2Q3", - "last_modified": "2023-02-17T00:02:53.037Z" - }, - { - "x": 2, - "y": 278, - "type": "TEXT", - "value": "Yolo Co-Davis/Woodland/Winters", - "last_modified": "2023-02-17T00:02:53.040Z" - }, - { - "x": 3, - "y": 278, - "type": "TEXT", - "value": "Davis/Woodland/Winters", - "last_modified": "2023-02-17T00:02:53.043Z" - }, - { - "x": 4, - "y": 278, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:53.046Z" - }, - { - "x": 5, - "y": 278, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.050Z" - }, - { - "x": 6, - "y": 278, - "type": "TEXT", - "value": "38.5790725", - "last_modified": "2023-02-17T00:02:53.053Z" - }, - { - "x": 7, - "y": 278, - "type": "TEXT", - "value": "-121.8566322", - "last_modified": "2023-02-17T00:02:53.056Z" - }, - { - "x": 0, - "y": 279, - "type": "TEXT", - "value": "276", - "last_modified": "2023-02-17T00:02:53.059Z" - }, - { - "x": 1, - "y": 279, - "type": "TEXT", - "value": "2R0", - "last_modified": "2023-02-17T00:02:53.063Z" - }, - { - "x": 2, - "y": 279, - "type": "TEXT", - "value": "Waynesboro Municipal", - "last_modified": "2023-02-17T00:02:53.066Z" - }, - { - "x": 3, - "y": 279, - "type": "TEXT", - "value": "Waynesboro", - "last_modified": "2023-02-17T00:02:53.069Z" - }, - { - "x": 4, - "y": 279, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:53.072Z" - }, - { - "x": 5, - "y": 279, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.076Z" - }, - { - "x": 6, - "y": 279, - "type": "TEXT", - "value": "31.64599472", - "last_modified": "2023-02-17T00:02:53.079Z" - }, - { - "x": 7, - "y": 279, - "type": "TEXT", - "value": "-88.63475667", - "last_modified": "2023-02-17T00:02:53.082Z" - }, - { - "x": 0, - "y": 280, - "type": "TEXT", - "value": "277", - "last_modified": "2023-02-17T00:02:53.085Z" - }, - { - "x": 1, - "y": 280, - "type": "TEXT", - "value": "2R4", - "last_modified": "2023-02-17T00:02:53.088Z" - }, - { - "x": 2, - "y": 280, - "type": "TEXT", - "value": "Peter Prince", - "last_modified": "2023-02-17T00:02:53.092Z" - }, - { - "x": 3, - "y": 280, - "type": "TEXT", - "value": "Milton", - "last_modified": "2023-02-17T00:02:53.095Z" - }, - { - "x": 4, - "y": 280, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:53.098Z" - }, - { - "x": 5, - "y": 280, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.101Z" - }, - { - "x": 6, - "y": 280, - "type": "TEXT", - "value": "30.63762083", - "last_modified": "2023-02-17T00:02:53.105Z" - }, - { - "x": 7, - "y": 280, - "type": "TEXT", - "value": "-86.99365278", - "last_modified": "2023-02-17T00:02:53.108Z" - }, - { - "x": 0, - "y": 281, - "type": "TEXT", - "value": "278", - "last_modified": "2023-02-17T00:02:53.111Z" - }, - { - "x": 1, - "y": 281, - "type": "TEXT", - "value": "2R5", - "last_modified": "2023-02-17T00:02:53.114Z" - }, - { - "x": 2, - "y": 281, - "type": "TEXT", - "value": "St Elmo", - "last_modified": "2023-02-17T00:02:53.117Z" - }, - { - "x": 3, - "y": 281, - "type": "TEXT", - "value": "St Elmo", - "last_modified": "2023-02-17T00:02:53.121Z" - }, - { - "x": 4, - "y": 281, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:53.124Z" - }, - { - "x": 5, - "y": 281, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.127Z" - }, - { - "x": 6, - "y": 281, - "type": "TEXT", - "value": "30.50190833", - "last_modified": "2023-02-17T00:02:53.130Z" - }, - { - "x": 7, - "y": 281, - "type": "TEXT", - "value": "-88.27511667", - "last_modified": "2023-02-17T00:02:53.133Z" - }, - { - "x": 0, - "y": 282, - "type": "TEXT", - "value": "279", - "last_modified": "2023-02-17T00:02:53.137Z" - }, - { - "x": 1, - "y": 282, - "type": "TEXT", - "value": "2R9", - "last_modified": "2023-02-17T00:02:53.140Z" - }, - { - "x": 2, - "y": 282, - "type": "TEXT", - "value": "Karnes County", - "last_modified": "2023-02-17T00:02:53.143Z" - }, - { - "x": 3, - "y": 282, - "type": "TEXT", - "value": "Kenedy", - "last_modified": "2023-02-17T00:02:53.146Z" - }, - { - "x": 4, - "y": 282, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:53.149Z" - }, - { - "x": 5, - "y": 282, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.152Z" - }, - { - "x": 6, - "y": 282, - "type": "TEXT", - "value": "28.8250075", - "last_modified": "2023-02-17T00:02:53.156Z" - }, - { - "x": 7, - "y": 282, - "type": "TEXT", - "value": "-97.86558333", - "last_modified": "2023-02-17T00:02:53.159Z" - }, - { - "x": 0, - "y": 283, - "type": "TEXT", - "value": "280", - "last_modified": "2023-02-17T00:02:53.162Z" - }, - { - "x": 1, - "y": 283, - "type": "TEXT", - "value": "2S1", - "last_modified": "2023-02-17T00:02:53.165Z" - }, - { - "x": 2, - "y": 283, - "type": "TEXT", - "value": "Vashon Municipal", - "last_modified": "2023-02-17T00:02:53.168Z" - }, - { - "x": 3, - "y": 283, - "type": "TEXT", - "value": "Vashon", - "last_modified": "2023-02-17T00:02:53.171Z" - }, - { - "x": 4, - "y": 283, - "type": "TEXT", - "value": "WA", - "last_modified": "2023-02-17T00:02:53.174Z" - }, - { - "x": 5, - "y": 283, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.178Z" - }, - { - "x": 6, - "y": 283, - "type": "TEXT", - "value": "47.45815333", - "last_modified": "2023-02-17T00:02:53.181Z" - }, - { - "x": 7, - "y": 283, - "type": "TEXT", - "value": "-122.4773506", - "last_modified": "2023-02-17T00:02:53.184Z" - }, - { - "x": 0, - "y": 284, - "type": "TEXT", - "value": "281", - "last_modified": "2023-02-17T00:02:53.187Z" - }, - { - "x": 1, - "y": 284, - "type": "TEXT", - "value": "2S6", - "last_modified": "2023-02-17T00:02:53.190Z" - }, - { - "x": 2, - "y": 284, - "type": "TEXT", - "value": "Sportsman Airpark", - "last_modified": "2023-02-17T00:02:53.193Z" - }, - { - "x": 3, - "y": 284, - "type": "TEXT", - "value": "Newberg", - "last_modified": "2023-02-17T00:02:53.196Z" - }, - { - "x": 4, - "y": 284, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:53.199Z" - }, - { - "x": 5, - "y": 284, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.203Z" - }, - { - "x": 6, - "y": 284, - "type": "TEXT", - "value": "45.29567333", - "last_modified": "2023-02-17T00:02:53.206Z" - }, - { - "x": 7, - "y": 284, - "type": "TEXT", - "value": "-122.9553783", - "last_modified": "2023-02-17T00:02:53.209Z" - }, - { - "x": 0, - "y": 285, - "type": "TEXT", - "value": "282", - "last_modified": "2023-02-17T00:02:53.212Z" - }, - { - "x": 1, - "y": 285, - "type": "TEXT", - "value": "2S7", - "last_modified": "2023-02-17T00:02:53.215Z" - }, - { - "x": 2, - "y": 285, - "type": "TEXT", - "value": "Chiloquin State", - "last_modified": "2023-02-17T00:02:53.218Z" - }, - { - "x": 3, - "y": 285, - "type": "TEXT", - "value": "Chiloquin", - "last_modified": "2023-02-17T00:02:53.221Z" - }, - { - "x": 4, - "y": 285, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:53.224Z" - }, - { - "x": 5, - "y": 285, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.227Z" - }, - { - "x": 6, - "y": 285, - "type": "TEXT", - "value": "42.58319167", - "last_modified": "2023-02-17T00:02:53.230Z" - }, - { - "x": 7, - "y": 285, - "type": "TEXT", - "value": "-121.8761261", - "last_modified": "2023-02-17T00:02:53.233Z" - }, - { - "x": 0, - "y": 286, - "type": "TEXT", - "value": "283", - "last_modified": "2023-02-17T00:02:53.237Z" - }, - { - "x": 1, - "y": 286, - "type": "TEXT", - "value": "2S8", - "last_modified": "2023-02-17T00:02:53.240Z" - }, - { - "x": 2, - "y": 286, - "type": "TEXT", - "value": "Wilbur", - "last_modified": "2023-02-17T00:02:53.243Z" - }, - { - "x": 3, - "y": 286, - "type": "TEXT", - "value": "Wilbur", - "last_modified": "2023-02-17T00:02:53.246Z" - }, - { - "x": 4, - "y": 286, - "type": "TEXT", - "value": "WA", - "last_modified": "2023-02-17T00:02:53.249Z" - }, - { - "x": 5, - "y": 286, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.252Z" - }, - { - "x": 6, - "y": 286, - "type": "TEXT", - "value": "47.75320639", - "last_modified": "2023-02-17T00:02:53.255Z" - }, - { - "x": 7, - "y": 286, - "type": "TEXT", - "value": "-118.7438936", - "last_modified": "2023-02-17T00:02:53.258Z" - }, - { - "x": 0, - "y": 287, - "type": "TEXT", - "value": "284", - "last_modified": "2023-02-17T00:02:53.261Z" - }, - { - "x": 1, - "y": 287, - "type": "TEXT", - "value": "2T1", - "last_modified": "2023-02-17T00:02:53.264Z" - }, - { - "x": 2, - "y": 287, - "type": "TEXT", - "value": "Muleshoe Municipal", - "last_modified": "2023-02-17T00:02:53.267Z" - }, - { - "x": 3, - "y": 287, - "type": "TEXT", - "value": "Muleshoe", - "last_modified": "2023-02-17T00:02:53.270Z" - }, - { - "x": 4, - "y": 287, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:53.273Z" - }, - { - "x": 5, - "y": 287, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.276Z" - }, - { - "x": 6, - "y": 287, - "type": "TEXT", - "value": "34.18513639", - "last_modified": "2023-02-17T00:02:53.279Z" - }, - { - "x": 7, - "y": 287, - "type": "TEXT", - "value": "-102.6410981", - "last_modified": "2023-02-17T00:02:53.282Z" - }, - { - "x": 0, - "y": 288, - "type": "TEXT", - "value": "285", - "last_modified": "2023-02-17T00:02:53.285Z" - }, - { - "x": 1, - "y": 288, - "type": "TEXT", - "value": "2V1", - "last_modified": "2023-02-17T00:02:53.288Z" - }, - { - "x": 2, - "y": 288, - "type": "TEXT", - "value": "Stevens", - "last_modified": "2023-02-17T00:02:53.291Z" - }, - { - "x": 3, - "y": 288, - "type": "TEXT", - "value": "Pagosa Springs", - "last_modified": "2023-02-17T00:02:53.294Z" - }, - { - "x": 4, - "y": 288, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:53.297Z" - }, - { - "x": 5, - "y": 288, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.300Z" - }, - { - "x": 6, - "y": 288, - "type": "TEXT", - "value": "37.277505", - "last_modified": "2023-02-17T00:02:53.303Z" - }, - { - "x": 7, - "y": 288, - "type": "TEXT", - "value": "-107.0558742", - "last_modified": "2023-02-17T00:02:53.306Z" - }, - { - "x": 0, - "y": 289, - "type": "TEXT", - "value": "286", - "last_modified": "2023-02-17T00:02:53.309Z" - }, - { - "x": 1, - "y": 289, - "type": "TEXT", - "value": "2V2", - "last_modified": "2023-02-17T00:02:53.312Z" - }, - { - "x": 2, - "y": 289, - "type": "TEXT", - "value": "Vance Brand", - "last_modified": "2023-02-17T00:02:53.315Z" - }, - { - "x": 3, - "y": 289, - "type": "TEXT", - "value": "Longmont", - "last_modified": "2023-02-17T00:02:53.318Z" - }, - { - "x": 4, - "y": 289, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:53.321Z" - }, - { - "x": 5, - "y": 289, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.324Z" - }, - { - "x": 6, - "y": 289, - "type": "TEXT", - "value": "40.16367139", - "last_modified": "2023-02-17T00:02:53.327Z" - }, - { - "x": 7, - "y": 289, - "type": "TEXT", - "value": "-105.1630369", - "last_modified": "2023-02-17T00:02:53.330Z" - }, - { - "x": 0, - "y": 290, - "type": "TEXT", - "value": "287", - "last_modified": "2023-02-17T00:02:53.333Z" - }, - { - "x": 1, - "y": 290, - "type": "TEXT", - "value": "2V5", - "last_modified": "2023-02-17T00:02:53.336Z" - }, - { - "x": 2, - "y": 290, - "type": "TEXT", - "value": "Wray Municipal", - "last_modified": "2023-02-17T00:02:53.339Z" - }, - { - "x": 3, - "y": 290, - "type": "TEXT", - "value": "Wray", - "last_modified": "2023-02-17T00:02:53.342Z" - }, - { - "x": 4, - "y": 290, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:53.345Z" - }, - { - "x": 5, - "y": 290, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.348Z" - }, - { - "x": 6, - "y": 290, - "type": "TEXT", - "value": "40.10032333", - "last_modified": "2023-02-17T00:02:53.351Z" - }, - { - "x": 7, - "y": 290, - "type": "TEXT", - "value": "-102.24096", - "last_modified": "2023-02-17T00:02:53.354Z" - }, - { - "x": 0, - "y": 291, - "type": "TEXT", - "value": "288", - "last_modified": "2023-02-17T00:02:53.357Z" - }, - { - "x": 1, - "y": 291, - "type": "TEXT", - "value": "2V6", - "last_modified": "2023-02-17T00:02:53.360Z" - }, - { - "x": 2, - "y": 291, - "type": "TEXT", - "value": "Yuma Municipal", - "last_modified": "2023-02-17T00:02:53.362Z" - }, - { - "x": 3, - "y": 291, - "type": "TEXT", - "value": "Yuma", - "last_modified": "2023-02-17T00:02:53.365Z" - }, - { - "x": 4, - "y": 291, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:53.368Z" - }, - { - "x": 5, - "y": 291, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.371Z" - }, - { - "x": 6, - "y": 291, - "type": "TEXT", - "value": "40.10415306", - "last_modified": "2023-02-17T00:02:53.374Z" - }, - { - "x": 7, - "y": 291, - "type": "TEXT", - "value": "-102.7129869", - "last_modified": "2023-02-17T00:02:53.377Z" - }, - { - "x": 0, - "y": 292, - "type": "TEXT", - "value": "289", - "last_modified": "2023-02-17T00:02:53.380Z" - }, - { - "x": 1, - "y": 292, - "type": "TEXT", - "value": "2W5", - "last_modified": "2023-02-17T00:02:53.383Z" - }, - { - "x": 2, - "y": 292, - "type": "TEXT", - "value": "Maryland", - "last_modified": "2023-02-17T00:02:53.386Z" - }, - { - "x": 3, - "y": 292, - "type": "TEXT", - "value": "Indian Head", - "last_modified": "2023-02-17T00:02:53.389Z" - }, - { - "x": 4, - "y": 292, - "type": "TEXT", - "value": "MD", - "last_modified": "2023-02-17T00:02:53.392Z" - }, - { - "x": 5, - "y": 292, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.395Z" - }, - { - "x": 6, - "y": 292, - "type": "TEXT", - "value": "38.60053667", - "last_modified": "2023-02-17T00:02:53.397Z" - }, - { - "x": 7, - "y": 292, - "type": "TEXT", - "value": "-77.07296917", - "last_modified": "2023-02-17T00:02:53.400Z" - }, - { - "x": 0, - "y": 293, - "type": "TEXT", - "value": "290", - "last_modified": "2023-02-17T00:02:53.403Z" - }, - { - "x": 1, - "y": 293, - "type": "TEXT", - "value": "2W6", - "last_modified": "2023-02-17T00:02:53.406Z" - }, - { - "x": 2, - "y": 293, - "type": "TEXT", - "value": "Captain Walter Francis Duke Regional", - "last_modified": "2023-02-17T00:02:53.409Z" - }, - { - "x": 3, - "y": 293, - "type": "TEXT", - "value": "Leonardtown", - "last_modified": "2023-02-17T00:02:53.412Z" - }, - { - "x": 4, - "y": 293, - "type": "TEXT", - "value": "MD", - "last_modified": "2023-02-17T00:02:53.415Z" - }, - { - "x": 5, - "y": 293, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.418Z" - }, - { - "x": 6, - "y": 293, - "type": "TEXT", - "value": "38.31536111", - "last_modified": "2023-02-17T00:02:53.421Z" - }, - { - "x": 7, - "y": 293, - "type": "TEXT", - "value": "-76.55011111", - "last_modified": "2023-02-17T00:02:53.423Z" - }, - { - "x": 0, - "y": 294, - "type": "TEXT", - "value": "291", - "last_modified": "2023-02-17T00:02:53.426Z" - }, - { - "x": 1, - "y": 294, - "type": "TEXT", - "value": "2Y3", - "last_modified": "2023-02-17T00:02:53.429Z" - }, - { - "x": 2, - "y": 294, - "type": "TEXT", - "value": "Yakutat SPB", - "last_modified": "2023-02-17T00:02:53.432Z" - }, - { - "x": 3, - "y": 294, - "type": "TEXT", - "value": "Yakutat", - "last_modified": "2023-02-17T00:02:53.435Z" - }, - { - "x": 4, - "y": 294, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:53.438Z" - }, - { - "x": 5, - "y": 294, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.441Z" - }, - { - "x": 6, - "y": 294, - "type": "TEXT", - "value": "59.5624775", - "last_modified": "2023-02-17T00:02:53.444Z" - }, - { - "x": 7, - "y": 294, - "type": "TEXT", - "value": "-139.7410994", - "last_modified": "2023-02-17T00:02:53.446Z" - }, - { - "x": 0, - "y": 295, - "type": "TEXT", - "value": "292", - "last_modified": "2023-02-17T00:02:53.449Z" - }, - { - "x": 1, - "y": 295, - "type": "TEXT", - "value": "2Y4", - "last_modified": "2023-02-17T00:02:53.452Z" - }, - { - "x": 2, - "y": 295, - "type": "TEXT", - "value": "Rockwell City Municipal", - "last_modified": "2023-02-17T00:02:53.455Z" - }, - { - "x": 3, - "y": 295, - "type": "TEXT", - "value": "Rockwell City", - "last_modified": "2023-02-17T00:02:53.458Z" - }, - { - "x": 4, - "y": 295, - "type": "TEXT", - "value": "IA", - "last_modified": "2023-02-17T00:02:53.461Z" - }, - { - "x": 5, - "y": 295, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.463Z" - }, - { - "x": 6, - "y": 295, - "type": "TEXT", - "value": "42.38748056", - "last_modified": "2023-02-17T00:02:53.466Z" - }, - { - "x": 7, - "y": 295, - "type": "TEXT", - "value": "-94.61803333", - "last_modified": "2023-02-17T00:02:53.469Z" - }, - { - "x": 0, - "y": 296, - "type": "TEXT", - "value": "293", - "last_modified": "2023-02-17T00:02:53.472Z" - }, - { - "x": 1, - "y": 296, - "type": "TEXT", - "value": "31F", - "last_modified": "2023-02-17T00:02:53.475Z" - }, - { - "x": 2, - "y": 296, - "type": "TEXT", - "value": "Gaines County", - "last_modified": "2023-02-17T00:02:53.477Z" - }, - { - "x": 3, - "y": 296, - "type": "TEXT", - "value": "Seminole", - "last_modified": "2023-02-17T00:02:53.480Z" - }, - { - "x": 4, - "y": 296, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:53.483Z" - }, - { - "x": 5, - "y": 296, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.486Z" - }, - { - "x": 6, - "y": 296, - "type": "TEXT", - "value": "32.67535389", - "last_modified": "2023-02-17T00:02:53.489Z" - }, - { - "x": 7, - "y": 296, - "type": "TEXT", - "value": "-102.652685", - "last_modified": "2023-02-17T00:02:53.492Z" - }, - { - "x": 0, - "y": 297, - "type": "TEXT", - "value": "294", - "last_modified": "2023-02-17T00:02:53.494Z" - }, - { - "x": 1, - "y": 297, - "type": "TEXT", - "value": "32M", - "last_modified": "2023-02-17T00:02:53.497Z" - }, - { - "x": 2, - "y": 297, - "type": "TEXT", - "value": "Norfolk", - "last_modified": "2023-02-17T00:02:53.500Z" - }, - { - "x": 3, - "y": 297, - "type": "TEXT", - "value": "Norfolk", - "last_modified": "2023-02-17T00:02:53.503Z" - }, - { - "x": 4, - "y": 297, - "type": "TEXT", - "value": "MA", - "last_modified": "2023-02-17T00:02:53.506Z" - }, - { - "x": 5, - "y": 297, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.508Z" - }, - { - "x": 6, - "y": 297, - "type": "TEXT", - "value": "42.12787528", - "last_modified": "2023-02-17T00:02:53.511Z" - }, - { - "x": 7, - "y": 297, - "type": "TEXT", - "value": "-71.37033556", - "last_modified": "2023-02-17T00:02:53.514Z" - }, - { - "x": 0, - "y": 298, - "type": "TEXT", - "value": "295", - "last_modified": "2023-02-17T00:02:53.517Z" - }, - { - "x": 1, - "y": 298, - "type": "TEXT", - "value": "32S", - "last_modified": "2023-02-17T00:02:53.519Z" - }, - { - "x": 2, - "y": 298, - "type": "TEXT", - "value": "Stevensville", - "last_modified": "2023-02-17T00:02:53.522Z" - }, - { - "x": 3, - "y": 298, - "type": "TEXT", - "value": "Stevensville", - "last_modified": "2023-02-17T00:02:53.525Z" - }, - { - "x": 4, - "y": 298, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:53.528Z" - }, - { - "x": 5, - "y": 298, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.530Z" - }, - { - "x": 6, - "y": 298, - "type": "TEXT", - "value": "46.52511111", - "last_modified": "2023-02-17T00:02:53.533Z" - }, - { - "x": 7, - "y": 298, - "type": "TEXT", - "value": "-114.0528056", - "last_modified": "2023-02-17T00:02:53.536Z" - }, - { - "x": 0, - "y": 299, - "type": "TEXT", - "value": "296", - "last_modified": "2023-02-17T00:02:53.539Z" - }, - { - "x": 1, - "y": 299, - "type": "TEXT", - "value": "33J", - "last_modified": "2023-02-17T00:02:53.541Z" - }, - { - "x": 2, - "y": 299, - "type": "TEXT", - "value": "Geneva Municipal", - "last_modified": "2023-02-17T00:02:53.544Z" - }, - { - "x": 3, - "y": 299, - "type": "TEXT", - "value": "Geneva", - "last_modified": "2023-02-17T00:02:53.547Z" - }, - { - "x": 4, - "y": 299, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:53.550Z" - }, - { - "x": 5, - "y": 299, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.552Z" - }, - { - "x": 6, - "y": 299, - "type": "TEXT", - "value": "31.05527778", - "last_modified": "2023-02-17T00:02:53.555Z" - }, - { - "x": 7, - "y": 299, - "type": "TEXT", - "value": "-85.88033333", - "last_modified": "2023-02-17T00:02:53.558Z" - }, - { - "x": 0, - "y": 300, - "type": "TEXT", - "value": "297", - "last_modified": "2023-02-17T00:02:53.560Z" - }, - { - "x": 1, - "y": 300, - "type": "TEXT", - "value": "33M", - "last_modified": "2023-02-17T00:02:53.563Z" - }, - { - "x": 2, - "y": 300, - "type": "TEXT", - "value": "Water Valley", - "last_modified": "2023-02-17T00:02:53.566Z" - }, - { - "x": 3, - "y": 300, - "type": "TEXT", - "value": "Water Valley", - "last_modified": "2023-02-17T00:02:53.568Z" - }, - { - "x": 4, - "y": 300, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:53.571Z" - }, - { - "x": 5, - "y": 300, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.574Z" - }, - { - "x": 6, - "y": 300, - "type": "TEXT", - "value": "34.16677639", - "last_modified": "2023-02-17T00:02:53.577Z" - }, - { - "x": 7, - "y": 300, - "type": "TEXT", - "value": "-89.68619722", - "last_modified": "2023-02-17T00:02:53.579Z" - }, - { - "x": 0, - "y": 301, - "type": "TEXT", - "value": "298", - "last_modified": "2023-02-17T00:02:53.582Z" - }, - { - "x": 1, - "y": 301, - "type": "TEXT", - "value": "33N", - "last_modified": "2023-02-17T00:02:53.585Z" - }, - { - "x": 2, - "y": 301, - "type": "TEXT", - "value": "Delaware Airpark", - "last_modified": "2023-02-17T00:02:53.587Z" - }, - { - "x": 3, - "y": 301, - "type": "TEXT", - "value": "Dover", - "last_modified": "2023-02-17T00:02:53.590Z" - }, - { - "x": 4, - "y": 301, - "type": "TEXT", - "value": "DE", - "last_modified": "2023-02-17T00:02:53.593Z" - }, - { - "x": 5, - "y": 301, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.595Z" - }, - { - "x": 6, - "y": 301, - "type": "TEXT", - "value": "39.21837556", - "last_modified": "2023-02-17T00:02:53.598Z" - }, - { - "x": 7, - "y": 301, - "type": "TEXT", - "value": "-75.59642667", - "last_modified": "2023-02-17T00:02:53.601Z" - }, - { - "x": 0, - "y": 302, - "type": "TEXT", - "value": "299", - "last_modified": "2023-02-17T00:02:53.603Z" - }, - { - "x": 1, - "y": 302, - "type": "TEXT", - "value": "33S", - "last_modified": "2023-02-17T00:02:53.606Z" - }, - { - "x": 2, - "y": 302, - "type": "TEXT", - "value": "Pru", - "last_modified": "2023-02-17T00:02:53.608Z" - }, - { - "x": 3, - "y": 302, - "type": "TEXT", - "value": "Ritzville", - "last_modified": "2023-02-17T00:02:53.611Z" - }, - { - "x": 4, - "y": 302, - "type": "TEXT", - "value": "WA", - "last_modified": "2023-02-17T00:02:53.614Z" - }, - { - "x": 5, - "y": 302, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.616Z" - }, - { - "x": 6, - "y": 302, - "type": "TEXT", - "value": "47.12487194", - "last_modified": "2023-02-17T00:02:53.619Z" - }, - { - "x": 7, - "y": 302, - "type": "TEXT", - "value": "-118.3927539", - "last_modified": "2023-02-17T00:02:53.622Z" - }, - { - "x": 0, - "y": 303, - "type": "TEXT", - "value": "300", - "last_modified": "2023-02-17T00:02:53.624Z" - }, - { - "x": 1, - "y": 303, - "type": "TEXT", - "value": "34A", - "last_modified": "2023-02-17T00:02:53.627Z" - }, - { - "x": 2, - "y": 303, - "type": "TEXT", - "value": "Laurens County", - "last_modified": "2023-02-17T00:02:53.630Z" - }, - { - "x": 3, - "y": 303, - "type": "TEXT", - "value": "Laurens", - "last_modified": "2023-02-17T00:02:53.632Z" - }, - { - "x": 4, - "y": 303, - "type": "TEXT", - "value": "SC", - "last_modified": "2023-02-17T00:02:53.635Z" - }, - { - "x": 5, - "y": 303, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.637Z" - }, - { - "x": 6, - "y": 303, - "type": "TEXT", - "value": "34.50705556", - "last_modified": "2023-02-17T00:02:53.640Z" - }, - { - "x": 7, - "y": 303, - "type": "TEXT", - "value": "-81.94719444", - "last_modified": "2023-02-17T00:02:53.643Z" - }, - { - "x": 0, - "y": 304, - "type": "TEXT", - "value": "301", - "last_modified": "2023-02-17T00:02:53.645Z" - }, - { - "x": 1, - "y": 304, - "type": "TEXT", - "value": "35A", - "last_modified": "2023-02-17T00:02:53.648Z" - }, - { - "x": 2, - "y": 304, - "type": "TEXT", - "value": "\"Union County", - "last_modified": "2023-02-17T00:02:53.650Z" - }, - { - "x": 3, - "y": 304, - "type": "TEXT", - "value": " Troy Shelton\"", - "last_modified": "2023-02-17T00:02:53.653Z" - }, - { - "x": 4, - "y": 304, - "type": "TEXT", - "value": "Union", - "last_modified": "2023-02-17T00:02:53.656Z" - }, - { - "x": 5, - "y": 304, - "type": "TEXT", - "value": "SC", - "last_modified": "2023-02-17T00:02:53.658Z" - }, - { - "x": 6, - "y": 304, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.661Z" - }, - { - "x": 7, - "y": 304, - "type": "TEXT", - "value": "34.68680111", - "last_modified": "2023-02-17T00:02:53.663Z" - }, - { - "x": 0, - "y": 305, - "type": "TEXT", - "value": "302", - "last_modified": "2023-02-17T00:02:53.666Z" - }, - { - "x": 1, - "y": 305, - "type": "TEXT", - "value": "35D", - "last_modified": "2023-02-17T00:02:53.669Z" - }, - { - "x": 2, - "y": 305, - "type": "TEXT", - "value": "Padgham", - "last_modified": "2023-02-17T00:02:53.671Z" - }, - { - "x": 3, - "y": 305, - "type": "TEXT", - "value": "Allegan", - "last_modified": "2023-02-17T00:02:53.674Z" - }, - { - "x": 4, - "y": 305, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:53.676Z" - }, - { - "x": 5, - "y": 305, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.679Z" - }, - { - "x": 6, - "y": 305, - "type": "TEXT", - "value": "42.53098278", - "last_modified": "2023-02-17T00:02:53.681Z" - }, - { - "x": 7, - "y": 305, - "type": "TEXT", - "value": "-85.82513556", - "last_modified": "2023-02-17T00:02:53.684Z" - }, - { - "x": 0, - "y": 306, - "type": "TEXT", - "value": "303", - "last_modified": "2023-02-17T00:02:53.687Z" - }, - { - "x": 1, - "y": 306, - "type": "TEXT", - "value": "35S", - "last_modified": "2023-02-17T00:02:53.689Z" - }, - { - "x": 2, - "y": 306, - "type": "TEXT", - "value": "Wasco State", - "last_modified": "2023-02-17T00:02:53.692Z" - }, - { - "x": 3, - "y": 306, - "type": "TEXT", - "value": "Wasco", - "last_modified": "2023-02-17T00:02:53.694Z" - }, - { - "x": 4, - "y": 306, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:53.697Z" - }, - { - "x": 5, - "y": 306, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.699Z" - }, - { - "x": 6, - "y": 306, - "type": "TEXT", - "value": "45.58944444", - "last_modified": "2023-02-17T00:02:53.702Z" - }, - { - "x": 7, - "y": 306, - "type": "TEXT", - "value": "-120.6741667", - "last_modified": "2023-02-17T00:02:53.704Z" - }, - { - "x": 0, - "y": 307, - "type": "TEXT", - "value": "304", - "last_modified": "2023-02-17T00:02:53.707Z" - }, - { - "x": 1, - "y": 307, - "type": "TEXT", - "value": "36K", - "last_modified": "2023-02-17T00:02:53.710Z" - }, - { - "x": 2, - "y": 307, - "type": "TEXT", - "value": "Lakin", - "last_modified": "2023-02-17T00:02:53.712Z" - }, - { - "x": 3, - "y": 307, - "type": "TEXT", - "value": "Lakin", - "last_modified": "2023-02-17T00:02:53.715Z" - }, - { - "x": 4, - "y": 307, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:53.717Z" - }, - { - "x": 5, - "y": 307, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.720Z" - }, - { - "x": 6, - "y": 307, - "type": "TEXT", - "value": "37.96946389", - "last_modified": "2023-02-17T00:02:53.722Z" - }, - { - "x": 7, - "y": 307, - "type": "TEXT", - "value": "-101.2554472", - "last_modified": "2023-02-17T00:02:53.725Z" - }, - { - "x": 0, - "y": 308, - "type": "TEXT", - "value": "305", - "last_modified": "2023-02-17T00:02:53.727Z" - }, - { - "x": 1, - "y": 308, - "type": "TEXT", - "value": "36S", - "last_modified": "2023-02-17T00:02:53.730Z" - }, - { - "x": 2, - "y": 308, - "type": "TEXT", - "value": "Happy Camp", - "last_modified": "2023-02-17T00:02:53.732Z" - }, - { - "x": 3, - "y": 308, - "type": "TEXT", - "value": "Happy Camp", - "last_modified": "2023-02-17T00:02:53.735Z" - }, - { - "x": 4, - "y": 308, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:53.737Z" - }, - { - "x": 5, - "y": 308, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.740Z" - }, - { - "x": 6, - "y": 308, - "type": "TEXT", - "value": "41.79067944", - "last_modified": "2023-02-17T00:02:53.742Z" - }, - { - "x": 7, - "y": 308, - "type": "TEXT", - "value": "-123.3889444", - "last_modified": "2023-02-17T00:02:53.745Z" - }, - { - "x": 0, - "y": 309, - "type": "TEXT", - "value": "306", - "last_modified": "2023-02-17T00:02:53.747Z" - }, - { - "x": 1, - "y": 309, - "type": "TEXT", - "value": "36U", - "last_modified": "2023-02-17T00:02:53.750Z" - }, - { - "x": 2, - "y": 309, - "type": "TEXT", - "value": "Heber City Municipal/Russ McDonald", - "last_modified": "2023-02-17T00:02:53.752Z" - }, - { - "x": 3, - "y": 309, - "type": "TEXT", - "value": "Heber", - "last_modified": "2023-02-17T00:02:53.755Z" - }, - { - "x": 4, - "y": 309, - "type": "TEXT", - "value": "UT", - "last_modified": "2023-02-17T00:02:53.757Z" - }, - { - "x": 5, - "y": 309, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.760Z" - }, - { - "x": 6, - "y": 309, - "type": "TEXT", - "value": "40.48180556", - "last_modified": "2023-02-17T00:02:53.762Z" - }, - { - "x": 7, - "y": 309, - "type": "TEXT", - "value": "-111.4288056", - "last_modified": "2023-02-17T00:02:53.765Z" - }, - { - "x": 0, - "y": 310, - "type": "TEXT", - "value": "307", - "last_modified": "2023-02-17T00:02:53.767Z" - }, - { - "x": 1, - "y": 310, - "type": "TEXT", - "value": "37T", - "last_modified": "2023-02-17T00:02:53.769Z" - }, - { - "x": 2, - "y": 310, - "type": "TEXT", - "value": "Calico Rock-Izard County", - "last_modified": "2023-02-17T00:02:53.772Z" - }, - { - "x": 3, - "y": 310, - "type": "TEXT", - "value": "Calico Rock", - "last_modified": "2023-02-17T00:02:53.774Z" - }, - { - "x": 4, - "y": 310, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:53.777Z" - }, - { - "x": 5, - "y": 310, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.779Z" - }, - { - "x": 6, - "y": 310, - "type": "TEXT", - "value": "36.16565278", - "last_modified": "2023-02-17T00:02:53.782Z" - }, - { - "x": 7, - "y": 310, - "type": "TEXT", - "value": "-92.14523611", - "last_modified": "2023-02-17T00:02:53.784Z" - }, - { - "x": 0, - "y": 311, - "type": "TEXT", - "value": "308", - "last_modified": "2023-02-17T00:02:53.787Z" - }, - { - "x": 1, - "y": 311, - "type": "TEXT", - "value": "37W", - "last_modified": "2023-02-17T00:02:53.789Z" - }, - { - "x": 2, - "y": 311, - "type": "TEXT", - "value": "Harnett County", - "last_modified": "2023-02-17T00:02:53.791Z" - }, - { - "x": 3, - "y": 311, - "type": "TEXT", - "value": "Erwin", - "last_modified": "2023-02-17T00:02:53.794Z" - }, - { - "x": 4, - "y": 311, - "type": "TEXT", - "value": "NC", - "last_modified": "2023-02-17T00:02:53.796Z" - }, - { - "x": 5, - "y": 311, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.799Z" - }, - { - "x": 6, - "y": 311, - "type": "TEXT", - "value": "35.37880028", - "last_modified": "2023-02-17T00:02:53.801Z" - }, - { - "x": 7, - "y": 311, - "type": "TEXT", - "value": "-78.73362917", - "last_modified": "2023-02-17T00:02:53.804Z" - }, - { - "x": 0, - "y": 312, - "type": "TEXT", - "value": "309", - "last_modified": "2023-02-17T00:02:53.806Z" - }, - { - "x": 1, - "y": 312, - "type": "TEXT", - "value": "38A", - "last_modified": "2023-02-17T00:02:53.808Z" - }, - { - "x": 2, - "y": 312, - "type": "TEXT", - "value": "Shaktoolik", - "last_modified": "2023-02-17T00:02:53.811Z" - }, - { - "x": 3, - "y": 312, - "type": "TEXT", - "value": "Shaktoolik", - "last_modified": "2023-02-17T00:02:53.813Z" - }, - { - "x": 4, - "y": 312, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:53.816Z" - }, - { - "x": 5, - "y": 312, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.818Z" - }, - { - "x": 6, - "y": 312, - "type": "TEXT", - "value": "64.36263194", - "last_modified": "2023-02-17T00:02:53.820Z" - }, - { - "x": 7, - "y": 312, - "type": "TEXT", - "value": "-161.2025369", - "last_modified": "2023-02-17T00:02:53.823Z" - }, - { - "x": 0, - "y": 313, - "type": "TEXT", - "value": "310", - "last_modified": "2023-02-17T00:02:53.825Z" - }, - { - "x": 1, - "y": 313, - "type": "TEXT", - "value": "38S", - "last_modified": "2023-02-17T00:02:53.828Z" - }, - { - "x": 2, - "y": 313, - "type": "TEXT", - "value": "Deer Lodge-City-County", - "last_modified": "2023-02-17T00:02:53.830Z" - }, - { - "x": 3, - "y": 313, - "type": "TEXT", - "value": "Deer Lodge", - "last_modified": "2023-02-17T00:02:53.832Z" - }, - { - "x": 4, - "y": 313, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:53.835Z" - }, - { - "x": 5, - "y": 313, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.837Z" - }, - { - "x": 6, - "y": 313, - "type": "TEXT", - "value": "46.38881583", - "last_modified": "2023-02-17T00:02:53.839Z" - }, - { - "x": 7, - "y": 313, - "type": "TEXT", - "value": "-112.7669842", - "last_modified": "2023-02-17T00:02:53.842Z" - }, - { - "x": 0, - "y": 314, - "type": "TEXT", - "value": "311", - "last_modified": "2023-02-17T00:02:53.844Z" - }, - { - "x": 1, - "y": 314, - "type": "TEXT", - "value": "38U", - "last_modified": "2023-02-17T00:02:53.847Z" - }, - { - "x": 2, - "y": 314, - "type": "TEXT", - "value": "Wayne Wonderland", - "last_modified": "2023-02-17T00:02:53.849Z" - }, - { - "x": 3, - "y": 314, - "type": "TEXT", - "value": "Loa", - "last_modified": "2023-02-17T00:02:53.851Z" - }, - { - "x": 4, - "y": 314, - "type": "TEXT", - "value": "UT", - "last_modified": "2023-02-17T00:02:53.854Z" - }, - { - "x": 5, - "y": 314, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.856Z" - }, - { - "x": 6, - "y": 314, - "type": "TEXT", - "value": "38.36247972", - "last_modified": "2023-02-17T00:02:53.858Z" - }, - { - "x": 7, - "y": 314, - "type": "TEXT", - "value": "-111.5960164", - "last_modified": "2023-02-17T00:02:53.861Z" - }, - { - "x": 0, - "y": 315, - "type": "TEXT", - "value": "312", - "last_modified": "2023-02-17T00:02:53.863Z" - }, - { - "x": 1, - "y": 315, - "type": "TEXT", - "value": "39N", - "last_modified": "2023-02-17T00:02:53.866Z" - }, - { - "x": 2, - "y": 315, - "type": "TEXT", - "value": "Princeton", - "last_modified": "2023-02-17T00:02:53.868Z" - }, - { - "x": 3, - "y": 315, - "type": "TEXT", - "value": "Princeton", - "last_modified": "2023-02-17T00:02:53.870Z" - }, - { - "x": 4, - "y": 315, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:53.873Z" - }, - { - "x": 5, - "y": 315, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.875Z" - }, - { - "x": 6, - "y": 315, - "type": "TEXT", - "value": "40.39834833", - "last_modified": "2023-02-17T00:02:53.877Z" - }, - { - "x": 7, - "y": 315, - "type": "TEXT", - "value": "-74.65760361", - "last_modified": "2023-02-17T00:02:53.880Z" - }, - { - "x": 0, - "y": 316, - "type": "TEXT", - "value": "313", - "last_modified": "2023-02-17T00:02:53.882Z" - }, - { - "x": 1, - "y": 316, - "type": "TEXT", - "value": "3A0", - "last_modified": "2023-02-17T00:02:53.884Z" - }, - { - "x": 2, - "y": 316, - "type": "TEXT", - "value": "Grove Hill Municipal", - "last_modified": "2023-02-17T00:02:53.887Z" - }, - { - "x": 3, - "y": 316, - "type": "TEXT", - "value": "Grove Hill", - "last_modified": "2023-02-17T00:02:53.889Z" - }, - { - "x": 4, - "y": 316, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:53.891Z" - }, - { - "x": 5, - "y": 316, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.893Z" - }, - { - "x": 6, - "y": 316, - "type": "TEXT", - "value": "31.68932389", - "last_modified": "2023-02-17T00:02:53.896Z" - }, - { - "x": 7, - "y": 316, - "type": "TEXT", - "value": "-87.7613875", - "last_modified": "2023-02-17T00:02:53.898Z" - }, - { - "x": 0, - "y": 317, - "type": "TEXT", - "value": "314", - "last_modified": "2023-02-17T00:02:53.900Z" - }, - { - "x": 1, - "y": 317, - "type": "TEXT", - "value": "3A1", - "last_modified": "2023-02-17T00:02:53.903Z" - }, - { - "x": 2, - "y": 317, - "type": "TEXT", - "value": "Folsom", - "last_modified": "2023-02-17T00:02:53.905Z" - }, - { - "x": 3, - "y": 317, - "type": "TEXT", - "value": "Cullman", - "last_modified": "2023-02-17T00:02:53.907Z" - }, - { - "x": 4, - "y": 317, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:53.910Z" - }, - { - "x": 5, - "y": 317, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.912Z" - }, - { - "x": 6, - "y": 317, - "type": "TEXT", - "value": "34.26870833", - "last_modified": "2023-02-17T00:02:53.914Z" - }, - { - "x": 7, - "y": 317, - "type": "TEXT", - "value": "-86.85833611", - "last_modified": "2023-02-17T00:02:53.917Z" - }, - { - "x": 0, - "y": 318, - "type": "TEXT", - "value": "315", - "last_modified": "2023-02-17T00:02:53.919Z" - }, - { - "x": 1, - "y": 318, - "type": "TEXT", - "value": "3A2", - "last_modified": "2023-02-17T00:02:53.921Z" - }, - { - "x": 2, - "y": 318, - "type": "TEXT", - "value": "New Tazewell Municipal", - "last_modified": "2023-02-17T00:02:53.923Z" - }, - { - "x": 3, - "y": 318, - "type": "TEXT", - "value": "Tazewell", - "last_modified": "2023-02-17T00:02:53.926Z" - }, - { - "x": 4, - "y": 318, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:53.928Z" - }, - { - "x": 5, - "y": 318, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.930Z" - }, - { - "x": 6, - "y": 318, - "type": "TEXT", - "value": "36.41008417", - "last_modified": "2023-02-17T00:02:53.932Z" - }, - { - "x": 7, - "y": 318, - "type": "TEXT", - "value": "-83.55546167", - "last_modified": "2023-02-17T00:02:53.935Z" - }, - { - "x": 0, - "y": 319, - "type": "TEXT", - "value": "316", - "last_modified": "2023-02-17T00:02:53.937Z" - }, - { - "x": 1, - "y": 319, - "type": "TEXT", - "value": "3A3", - "last_modified": "2023-02-17T00:02:53.939Z" - }, - { - "x": 2, - "y": 319, - "type": "TEXT", - "value": "Anson County", - "last_modified": "2023-02-17T00:02:53.941Z" - }, - { - "x": 3, - "y": 319, - "type": "TEXT", - "value": "Wadesboro", - "last_modified": "2023-02-17T00:02:53.944Z" - }, - { - "x": 4, - "y": 319, - "type": "TEXT", - "value": "NC", - "last_modified": "2023-02-17T00:02:53.946Z" - }, - { - "x": 5, - "y": 319, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.948Z" - }, - { - "x": 6, - "y": 319, - "type": "TEXT", - "value": "35.02397611", - "last_modified": "2023-02-17T00:02:53.950Z" - }, - { - "x": 7, - "y": 319, - "type": "TEXT", - "value": "-80.08127333", - "last_modified": "2023-02-17T00:02:53.953Z" - }, - { - "x": 0, - "y": 320, - "type": "TEXT", - "value": "317", - "last_modified": "2023-02-17T00:02:53.955Z" - }, - { - "x": 1, - "y": 320, - "type": "TEXT", - "value": "3AU", - "last_modified": "2023-02-17T00:02:53.957Z" - }, - { - "x": 2, - "y": 320, - "type": "TEXT", - "value": "Augusta Municipal", - "last_modified": "2023-02-17T00:02:53.959Z" - }, - { - "x": 3, - "y": 320, - "type": "TEXT", - "value": "Augusta", - "last_modified": "2023-02-17T00:02:53.961Z" - }, - { - "x": 4, - "y": 320, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:53.964Z" - }, - { - "x": 5, - "y": 320, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.966Z" - }, - { - "x": 6, - "y": 320, - "type": "TEXT", - "value": "37.67162778", - "last_modified": "2023-02-17T00:02:53.968Z" - }, - { - "x": 7, - "y": 320, - "type": "TEXT", - "value": "-97.07787222", - "last_modified": "2023-02-17T00:02:53.971Z" - }, - { - "x": 0, - "y": 321, - "type": "TEXT", - "value": "318", - "last_modified": "2023-02-17T00:02:53.973Z" - }, - { - "x": 1, - "y": 321, - "type": "TEXT", - "value": "3B0", - "last_modified": "2023-02-17T00:02:53.975Z" - }, - { - "x": 2, - "y": 321, - "type": "TEXT", - "value": "Southbridge Municipal", - "last_modified": "2023-02-17T00:02:53.977Z" - }, - { - "x": 3, - "y": 321, - "type": "TEXT", - "value": "Southbridge", - "last_modified": "2023-02-17T00:02:53.979Z" - }, - { - "x": 4, - "y": 321, - "type": "TEXT", - "value": "MA", - "last_modified": "2023-02-17T00:02:53.982Z" - }, - { - "x": 5, - "y": 321, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:53.984Z" - }, - { - "x": 6, - "y": 321, - "type": "TEXT", - "value": "42.10092806", - "last_modified": "2023-02-17T00:02:53.986Z" - }, - { - "x": 7, - "y": 321, - "type": "TEXT", - "value": "-72.03840833", - "last_modified": "2023-02-17T00:02:53.988Z" - }, - { - "x": 0, - "y": 322, - "type": "TEXT", - "value": "319", - "last_modified": "2023-02-17T00:02:53.990Z" - }, - { - "x": 1, - "y": 322, - "type": "TEXT", - "value": "3B1", - "last_modified": "2023-02-17T00:02:53.992Z" - }, - { - "x": 2, - "y": 322, - "type": "TEXT", - "value": "Greenville Municipal", - "last_modified": "2023-02-17T00:02:53.995Z" - }, - { - "x": 3, - "y": 322, - "type": "TEXT", - "value": "Greenville", - "last_modified": "2023-02-17T00:02:53.997Z" - }, - { - "x": 4, - "y": 322, - "type": "TEXT", - "value": "ME", - "last_modified": "2023-02-17T00:02:53.999Z" - }, - { - "x": 5, - "y": 322, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.001Z" - }, - { - "x": 6, - "y": 322, - "type": "TEXT", - "value": "45.46302778", - "last_modified": "2023-02-17T00:02:54.003Z" - }, - { - "x": 7, - "y": 322, - "type": "TEXT", - "value": "-69.55161111", - "last_modified": "2023-02-17T00:02:54.005Z" - }, - { - "x": 0, - "y": 323, - "type": "TEXT", - "value": "320", - "last_modified": "2023-02-17T00:02:54.008Z" - }, - { - "x": 1, - "y": 323, - "type": "TEXT", - "value": "3B2", - "last_modified": "2023-02-17T00:02:54.010Z" - }, - { - "x": 2, - "y": 323, - "type": "TEXT", - "value": "Marshfield", - "last_modified": "2023-02-17T00:02:54.012Z" - }, - { - "x": 3, - "y": 323, - "type": "TEXT", - "value": "Marshfield", - "last_modified": "2023-02-17T00:02:54.014Z" - }, - { - "x": 4, - "y": 323, - "type": "TEXT", - "value": "MA", - "last_modified": "2023-02-17T00:02:54.016Z" - }, - { - "x": 5, - "y": 323, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.018Z" - }, - { - "x": 6, - "y": 323, - "type": "TEXT", - "value": "42.09824111", - "last_modified": "2023-02-17T00:02:54.021Z" - }, - { - "x": 7, - "y": 323, - "type": "TEXT", - "value": "-70.67212083", - "last_modified": "2023-02-17T00:02:54.023Z" - }, - { - "x": 0, - "y": 324, - "type": "TEXT", - "value": "321", - "last_modified": "2023-02-17T00:02:54.025Z" - }, - { - "x": 1, - "y": 324, - "type": "TEXT", - "value": "3B9", - "last_modified": "2023-02-17T00:02:54.027Z" - }, - { - "x": 2, - "y": 324, - "type": "TEXT", - "value": "Chester", - "last_modified": "2023-02-17T00:02:54.029Z" - }, - { - "x": 3, - "y": 324, - "type": "TEXT", - "value": "Chester", - "last_modified": "2023-02-17T00:02:54.031Z" - }, - { - "x": 4, - "y": 324, - "type": "TEXT", - "value": "CT", - "last_modified": "2023-02-17T00:02:54.033Z" - }, - { - "x": 5, - "y": 324, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.036Z" - }, - { - "x": 6, - "y": 324, - "type": "TEXT", - "value": "41.38390472", - "last_modified": "2023-02-17T00:02:54.038Z" - }, - { - "x": 7, - "y": 324, - "type": "TEXT", - "value": "-72.50589444", - "last_modified": "2023-02-17T00:02:54.040Z" - }, - { - "x": 0, - "y": 325, - "type": "TEXT", - "value": "322", - "last_modified": "2023-02-17T00:02:54.042Z" - }, - { - "x": 1, - "y": 325, - "type": "TEXT", - "value": "3BS", - "last_modified": "2023-02-17T00:02:54.044Z" - }, - { - "x": 2, - "y": 325, - "type": "TEXT", - "value": "Jack Barstow", - "last_modified": "2023-02-17T00:02:54.046Z" - }, - { - "x": 3, - "y": 325, - "type": "TEXT", - "value": "Midland", - "last_modified": "2023-02-17T00:02:54.048Z" - }, - { - "x": 4, - "y": 325, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:54.050Z" - }, - { - "x": 5, - "y": 325, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.052Z" - }, - { - "x": 6, - "y": 325, - "type": "TEXT", - "value": "43.66291528", - "last_modified": "2023-02-17T00:02:54.055Z" - }, - { - "x": 7, - "y": 325, - "type": "TEXT", - "value": "-84.261325", - "last_modified": "2023-02-17T00:02:54.057Z" - }, - { - "x": 0, - "y": 326, - "type": "TEXT", - "value": "323", - "last_modified": "2023-02-17T00:02:54.059Z" - }, - { - "x": 1, - "y": 326, - "type": "TEXT", - "value": "3CK", - "last_modified": "2023-02-17T00:02:54.061Z" - }, - { - "x": 2, - "y": 326, - "type": "TEXT", - "value": "Lake In The Hills", - "last_modified": "2023-02-17T00:02:54.063Z" - }, - { - "x": 3, - "y": 326, - "type": "TEXT", - "value": "Lake In The Hills", - "last_modified": "2023-02-17T00:02:54.065Z" - }, - { - "x": 4, - "y": 326, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:54.067Z" - }, - { - "x": 5, - "y": 326, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.069Z" - }, - { - "x": 6, - "y": 326, - "type": "TEXT", - "value": "42.20680306", - "last_modified": "2023-02-17T00:02:54.071Z" - }, - { - "x": 7, - "y": 326, - "type": "TEXT", - "value": "-88.32304028", - "last_modified": "2023-02-17T00:02:54.073Z" - }, - { - "x": 0, - "y": 327, - "type": "TEXT", - "value": "324", - "last_modified": "2023-02-17T00:02:54.075Z" - }, - { - "x": 1, - "y": 327, - "type": "TEXT", - "value": "3CM", - "last_modified": "2023-02-17T00:02:54.077Z" - }, - { - "x": 2, - "y": 327, - "type": "TEXT", - "value": "James Clements Municipal", - "last_modified": "2023-02-17T00:02:54.079Z" - }, - { - "x": 3, - "y": 327, - "type": "TEXT", - "value": "Bay City", - "last_modified": "2023-02-17T00:02:54.082Z" - }, - { - "x": 4, - "y": 327, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:54.084Z" - }, - { - "x": 5, - "y": 327, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.086Z" - }, - { - "x": 6, - "y": 327, - "type": "TEXT", - "value": "43.54691667", - "last_modified": "2023-02-17T00:02:54.088Z" - }, - { - "x": 7, - "y": 327, - "type": "TEXT", - "value": "-83.89550222", - "last_modified": "2023-02-17T00:02:54.090Z" - }, - { - "x": 0, - "y": 328, - "type": "TEXT", - "value": "325", - "last_modified": "2023-02-17T00:02:54.092Z" - }, - { - "x": 1, - "y": 328, - "type": "TEXT", - "value": "3CU", - "last_modified": "2023-02-17T00:02:54.094Z" - }, - { - "x": 2, - "y": 328, - "type": "TEXT", - "value": "Cable Union", - "last_modified": "2023-02-17T00:02:54.096Z" - }, - { - "x": 3, - "y": 328, - "type": "TEXT", - "value": "Cable", - "last_modified": "2023-02-17T00:02:54.098Z" - }, - { - "x": 4, - "y": 328, - "type": "TEXT", - "value": "WI", - "last_modified": "2023-02-17T00:02:54.100Z" - }, - { - "x": 5, - "y": 328, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.102Z" - }, - { - "x": 6, - "y": 328, - "type": "TEXT", - "value": "46.19424889", - "last_modified": "2023-02-17T00:02:54.104Z" - }, - { - "x": 7, - "y": 328, - "type": "TEXT", - "value": "-91.24640972", - "last_modified": "2023-02-17T00:02:54.106Z" - }, - { - "x": 0, - "y": 329, - "type": "TEXT", - "value": "326", - "last_modified": "2023-02-17T00:02:54.108Z" - }, - { - "x": 1, - "y": 329, - "type": "TEXT", - "value": "3D2", - "last_modified": "2023-02-17T00:02:54.110Z" - }, - { - "x": 2, - "y": 329, - "type": "TEXT", - "value": "Ephraim/Gibraltar", - "last_modified": "2023-02-17T00:02:54.112Z" - }, - { - "x": 3, - "y": 329, - "type": "TEXT", - "value": "Ephraim", - "last_modified": "2023-02-17T00:02:54.114Z" - }, - { - "x": 4, - "y": 329, - "type": "TEXT", - "value": "WI", - "last_modified": "2023-02-17T00:02:54.116Z" - }, - { - "x": 5, - "y": 329, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.118Z" - }, - { - "x": 6, - "y": 329, - "type": "TEXT", - "value": "45.13535778", - "last_modified": "2023-02-17T00:02:54.120Z" - }, - { - "x": 7, - "y": 329, - "type": "TEXT", - "value": "-87.18586556", - "last_modified": "2023-02-17T00:02:54.122Z" - }, - { - "x": 0, - "y": 330, - "type": "TEXT", - "value": "327", - "last_modified": "2023-02-17T00:02:54.124Z" - }, - { - "x": 1, - "y": 330, - "type": "TEXT", - "value": "3D4", - "last_modified": "2023-02-17T00:02:54.126Z" - }, - { - "x": 2, - "y": 330, - "type": "TEXT", - "value": "Frankfort Dow Memorial", - "last_modified": "2023-02-17T00:02:54.128Z" - }, - { - "x": 3, - "y": 330, - "type": "TEXT", - "value": "Frankfort", - "last_modified": "2023-02-17T00:02:54.130Z" - }, - { - "x": 4, - "y": 330, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:54.132Z" - }, - { - "x": 5, - "y": 330, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.134Z" - }, - { - "x": 6, - "y": 330, - "type": "TEXT", - "value": "44.62506389", - "last_modified": "2023-02-17T00:02:54.136Z" - }, - { - "x": 7, - "y": 330, - "type": "TEXT", - "value": "-86.20061944", - "last_modified": "2023-02-17T00:02:54.138Z" - }, - { - "x": 0, - "y": 331, - "type": "TEXT", - "value": "328", - "last_modified": "2023-02-17T00:02:54.140Z" - }, - { - "x": 1, - "y": 331, - "type": "TEXT", - "value": "3F3", - "last_modified": "2023-02-17T00:02:54.142Z" - }, - { - "x": 2, - "y": 331, - "type": "TEXT", - "value": "De Soto Parish", - "last_modified": "2023-02-17T00:02:54.144Z" - }, - { - "x": 3, - "y": 331, - "type": "TEXT", - "value": "Mansfield", - "last_modified": "2023-02-17T00:02:54.146Z" - }, - { - "x": 4, - "y": 331, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:54.148Z" - }, - { - "x": 5, - "y": 331, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.150Z" - }, - { - "x": 6, - "y": 331, - "type": "TEXT", - "value": "32.07345972", - "last_modified": "2023-02-17T00:02:54.152Z" - }, - { - "x": 7, - "y": 331, - "type": "TEXT", - "value": "-93.76551889", - "last_modified": "2023-02-17T00:02:54.154Z" - }, - { - "x": 0, - "y": 332, - "type": "TEXT", - "value": "329", - "last_modified": "2023-02-17T00:02:54.156Z" - }, - { - "x": 1, - "y": 332, - "type": "TEXT", - "value": "3F4", - "last_modified": "2023-02-17T00:02:54.158Z" - }, - { - "x": 2, - "y": 332, - "type": "TEXT", - "value": "Vivian", - "last_modified": "2023-02-17T00:02:54.160Z" - }, - { - "x": 3, - "y": 332, - "type": "TEXT", - "value": "Vivian", - "last_modified": "2023-02-17T00:02:54.162Z" - }, - { - "x": 4, - "y": 332, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:54.164Z" - }, - { - "x": 5, - "y": 332, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.166Z" - }, - { - "x": 6, - "y": 332, - "type": "TEXT", - "value": "32.86133333", - "last_modified": "2023-02-17T00:02:54.168Z" - }, - { - "x": 7, - "y": 332, - "type": "TEXT", - "value": "-94.01015361", - "last_modified": "2023-02-17T00:02:54.170Z" - }, - { - "x": 0, - "y": 333, - "type": "TEXT", - "value": "330", - "last_modified": "2023-02-17T00:02:54.171Z" - }, - { - "x": 1, - "y": 333, - "type": "TEXT", - "value": "3F7", - "last_modified": "2023-02-17T00:02:54.173Z" - }, - { - "x": 2, - "y": 333, - "type": "TEXT", - "value": "Jones Memorial", - "last_modified": "2023-02-17T00:02:54.175Z" - }, - { - "x": 3, - "y": 333, - "type": "TEXT", - "value": "Bristow", - "last_modified": "2023-02-17T00:02:54.177Z" - }, - { - "x": 4, - "y": 333, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:54.179Z" - }, - { - "x": 5, - "y": 333, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.181Z" - }, - { - "x": 6, - "y": 333, - "type": "TEXT", - "value": "35.80685278", - "last_modified": "2023-02-17T00:02:54.183Z" - }, - { - "x": 7, - "y": 333, - "type": "TEXT", - "value": "-96.42185556", - "last_modified": "2023-02-17T00:02:54.185Z" - }, - { - "x": 0, - "y": 334, - "type": "TEXT", - "value": "331", - "last_modified": "2023-02-17T00:02:54.187Z" - }, - { - "x": 1, - "y": 334, - "type": "TEXT", - "value": "3FM", - "last_modified": "2023-02-17T00:02:54.189Z" - }, - { - "x": 2, - "y": 334, - "type": "TEXT", - "value": "Fremont Municipal", - "last_modified": "2023-02-17T00:02:54.191Z" - }, - { - "x": 3, - "y": 334, - "type": "TEXT", - "value": "Fremont", - "last_modified": "2023-02-17T00:02:54.193Z" - }, - { - "x": 4, - "y": 334, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:54.195Z" - }, - { - "x": 5, - "y": 334, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.197Z" - }, - { - "x": 6, - "y": 334, - "type": "TEXT", - "value": "43.43890528", - "last_modified": "2023-02-17T00:02:54.199Z" - }, - { - "x": 7, - "y": 334, - "type": "TEXT", - "value": "-85.99478", - "last_modified": "2023-02-17T00:02:54.201Z" - }, - { - "x": 0, - "y": 335, - "type": "TEXT", - "value": "332", - "last_modified": "2023-02-17T00:02:54.202Z" - }, - { - "x": 1, - "y": 335, - "type": "TEXT", - "value": "3FU", - "last_modified": "2023-02-17T00:02:54.204Z" - }, - { - "x": 2, - "y": 335, - "type": "TEXT", - "value": "Faulkton Municipal", - "last_modified": "2023-02-17T00:02:54.206Z" - }, - { - "x": 3, - "y": 335, - "type": "TEXT", - "value": "Faulkton", - "last_modified": "2023-02-17T00:02:54.208Z" - }, - { - "x": 4, - "y": 335, - "type": "TEXT", - "value": "SD", - "last_modified": "2023-02-17T00:02:54.210Z" - }, - { - "x": 5, - "y": 335, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.212Z" - }, - { - "x": 6, - "y": 335, - "type": "TEXT", - "value": "45.03191861", - "last_modified": "2023-02-17T00:02:54.214Z" - }, - { - "x": 7, - "y": 335, - "type": "TEXT", - "value": "-99.11566417", - "last_modified": "2023-02-17T00:02:54.216Z" - }, - { - "x": 0, - "y": 336, - "type": "TEXT", - "value": "333", - "last_modified": "2023-02-17T00:02:54.217Z" - }, - { - "x": 1, - "y": 336, - "type": "TEXT", - "value": "3G3", - "last_modified": "2023-02-17T00:02:54.219Z" - }, - { - "x": 2, - "y": 336, - "type": "TEXT", - "value": "Wadsworth Municipal", - "last_modified": "2023-02-17T00:02:54.221Z" - }, - { - "x": 3, - "y": 336, - "type": "TEXT", - "value": "Wadsworth", - "last_modified": "2023-02-17T00:02:54.223Z" - }, - { - "x": 4, - "y": 336, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:54.225Z" - }, - { - "x": 5, - "y": 336, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.227Z" - }, - { - "x": 6, - "y": 336, - "type": "TEXT", - "value": "41.00158222", - "last_modified": "2023-02-17T00:02:54.229Z" - }, - { - "x": 7, - "y": 336, - "type": "TEXT", - "value": "-81.75513111", - "last_modified": "2023-02-17T00:02:54.231Z" - }, - { - "x": 0, - "y": 337, - "type": "TEXT", - "value": "334", - "last_modified": "2023-02-17T00:02:54.232Z" - }, - { - "x": 1, - "y": 337, - "type": "TEXT", - "value": "3G4", - "last_modified": "2023-02-17T00:02:54.234Z" - }, - { - "x": 2, - "y": 337, - "type": "TEXT", - "value": "Ashland County", - "last_modified": "2023-02-17T00:02:54.236Z" - }, - { - "x": 3, - "y": 337, - "type": "TEXT", - "value": "Ashland", - "last_modified": "2023-02-17T00:02:54.238Z" - }, - { - "x": 4, - "y": 337, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:54.240Z" - }, - { - "x": 5, - "y": 337, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.242Z" - }, - { - "x": 6, - "y": 337, - "type": "TEXT", - "value": "40.90297222", - "last_modified": "2023-02-17T00:02:54.243Z" - }, - { - "x": 7, - "y": 337, - "type": "TEXT", - "value": "-82.25563889", - "last_modified": "2023-02-17T00:02:54.245Z" - }, - { - "x": 0, - "y": 338, - "type": "TEXT", - "value": "335", - "last_modified": "2023-02-17T00:02:54.247Z" - }, - { - "x": 1, - "y": 338, - "type": "TEXT", - "value": "3G7", - "last_modified": "2023-02-17T00:02:54.249Z" - }, - { - "x": 2, - "y": 338, - "type": "TEXT", - "value": "Williamson/Sodus", - "last_modified": "2023-02-17T00:02:54.251Z" - }, - { - "x": 3, - "y": 338, - "type": "TEXT", - "value": "Williamson", - "last_modified": "2023-02-17T00:02:54.253Z" - }, - { - "x": 4, - "y": 338, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:54.254Z" - }, - { - "x": 5, - "y": 338, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.256Z" - }, - { - "x": 6, - "y": 338, - "type": "TEXT", - "value": "43.23472222", - "last_modified": "2023-02-17T00:02:54.258Z" - }, - { - "x": 7, - "y": 338, - "type": "TEXT", - "value": "-77.12097222", - "last_modified": "2023-02-17T00:02:54.260Z" - }, - { - "x": 0, - "y": 339, - "type": "TEXT", - "value": "336", - "last_modified": "2023-02-17T00:02:54.262Z" - }, - { - "x": 1, - "y": 339, - "type": "TEXT", - "value": "3GM", - "last_modified": "2023-02-17T00:02:54.264Z" - }, - { - "x": 2, - "y": 339, - "type": "TEXT", - "value": "Grand Haven Memorial Airpark", - "last_modified": "2023-02-17T00:02:54.265Z" - }, - { - "x": 3, - "y": 339, - "type": "TEXT", - "value": "Grand Haven", - "last_modified": "2023-02-17T00:02:54.267Z" - }, - { - "x": 4, - "y": 339, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:54.269Z" - }, - { - "x": 5, - "y": 339, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.271Z" - }, - { - "x": 6, - "y": 339, - "type": "TEXT", - "value": "43.03404639", - "last_modified": "2023-02-17T00:02:54.273Z" - }, - { - "x": 7, - "y": 339, - "type": "TEXT", - "value": "-86.1981625", - "last_modified": "2023-02-17T00:02:54.274Z" - }, - { - "x": 0, - "y": 340, - "type": "TEXT", - "value": "337", - "last_modified": "2023-02-17T00:02:54.276Z" - }, - { - "x": 1, - "y": 340, - "type": "TEXT", - "value": "3I2", - "last_modified": "2023-02-17T00:02:54.278Z" - }, - { - "x": 2, - "y": 340, - "type": "TEXT", - "value": "Mason County", - "last_modified": "2023-02-17T00:02:54.280Z" - }, - { - "x": 3, - "y": 340, - "type": "TEXT", - "value": "Point Pleasant", - "last_modified": "2023-02-17T00:02:54.282Z" - }, - { - "x": 4, - "y": 340, - "type": "TEXT", - "value": "WV", - "last_modified": "2023-02-17T00:02:54.283Z" - }, - { - "x": 5, - "y": 340, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.285Z" - }, - { - "x": 6, - "y": 340, - "type": "TEXT", - "value": "38.91463889", - "last_modified": "2023-02-17T00:02:54.287Z" - }, - { - "x": 7, - "y": 340, - "type": "TEXT", - "value": "-82.09858333", - "last_modified": "2023-02-17T00:02:54.289Z" - }, - { - "x": 0, - "y": 341, - "type": "TEXT", - "value": "338", - "last_modified": "2023-02-17T00:02:54.290Z" - }, - { - "x": 1, - "y": 341, - "type": "TEXT", - "value": "3I7", - "last_modified": "2023-02-17T00:02:54.292Z" - }, - { - "x": 2, - "y": 341, - "type": "TEXT", - "value": "Phillipsburg", - "last_modified": "2023-02-17T00:02:54.294Z" - }, - { - "x": 3, - "y": 341, - "type": "TEXT", - "value": "Phillipsburg", - "last_modified": "2023-02-17T00:02:54.296Z" - }, - { - "x": 4, - "y": 341, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:54.298Z" - }, - { - "x": 5, - "y": 341, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.299Z" - }, - { - "x": 6, - "y": 341, - "type": "TEXT", - "value": "39.91344194", - "last_modified": "2023-02-17T00:02:54.301Z" - }, - { - "x": 7, - "y": 341, - "type": "TEXT", - "value": "-84.40030889", - "last_modified": "2023-02-17T00:02:54.303Z" - }, - { - "x": 0, - "y": 342, - "type": "TEXT", - "value": "339", - "last_modified": "2023-02-17T00:02:54.305Z" - }, - { - "x": 1, - "y": 342, - "type": "TEXT", - "value": "3J1", - "last_modified": "2023-02-17T00:02:54.306Z" - }, - { - "x": 2, - "y": 342, - "type": "TEXT", - "value": "Ridgeland", - "last_modified": "2023-02-17T00:02:54.308Z" - }, - { - "x": 3, - "y": 342, - "type": "TEXT", - "value": "Ridgeland", - "last_modified": "2023-02-17T00:02:54.310Z" - }, - { - "x": 4, - "y": 342, - "type": "TEXT", - "value": "SC", - "last_modified": "2023-02-17T00:02:54.312Z" - }, - { - "x": 5, - "y": 342, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.313Z" - }, - { - "x": 6, - "y": 342, - "type": "TEXT", - "value": "32.49268694", - "last_modified": "2023-02-17T00:02:54.315Z" - }, - { - "x": 7, - "y": 342, - "type": "TEXT", - "value": "-80.99233028", - "last_modified": "2023-02-17T00:02:54.317Z" - }, - { - "x": 0, - "y": 343, - "type": "TEXT", - "value": "340", - "last_modified": "2023-02-17T00:02:54.318Z" - }, - { - "x": 1, - "y": 343, - "type": "TEXT", - "value": "3J7", - "last_modified": "2023-02-17T00:02:54.320Z" - }, - { - "x": 2, - "y": 343, - "type": "TEXT", - "value": "Greene County Airpark", - "last_modified": "2023-02-17T00:02:54.322Z" - }, - { - "x": 3, - "y": 343, - "type": "TEXT", - "value": "Greensboro", - "last_modified": "2023-02-17T00:02:54.324Z" - }, - { - "x": 4, - "y": 343, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:54.325Z" - }, - { - "x": 5, - "y": 343, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.327Z" - }, - { - "x": 6, - "y": 343, - "type": "TEXT", - "value": "33.59766667", - "last_modified": "2023-02-17T00:02:54.329Z" - }, - { - "x": 7, - "y": 343, - "type": "TEXT", - "value": "-83.139", - "last_modified": "2023-02-17T00:02:54.331Z" - }, - { - "x": 0, - "y": 344, - "type": "TEXT", - "value": "341", - "last_modified": "2023-02-17T00:02:54.332Z" - }, - { - "x": 1, - "y": 344, - "type": "TEXT", - "value": "3JC", - "last_modified": "2023-02-17T00:02:54.334Z" - }, - { - "x": 2, - "y": 344, - "type": "TEXT", - "value": "Freeman", - "last_modified": "2023-02-17T00:02:54.336Z" - }, - { - "x": 3, - "y": 344, - "type": "TEXT", - "value": "Junction City", - "last_modified": "2023-02-17T00:02:54.337Z" - }, - { - "x": 4, - "y": 344, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:54.339Z" - }, - { - "x": 5, - "y": 344, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.341Z" - }, - { - "x": 6, - "y": 344, - "type": "TEXT", - "value": "39.04327556", - "last_modified": "2023-02-17T00:02:54.343Z" - }, - { - "x": 7, - "y": 344, - "type": "TEXT", - "value": "-96.84328694", - "last_modified": "2023-02-17T00:02:54.344Z" - }, - { - "x": 0, - "y": 345, - "type": "TEXT", - "value": "342", - "last_modified": "2023-02-17T00:02:54.346Z" - }, - { - "x": 1, - "y": 345, - "type": "TEXT", - "value": "3K3", - "last_modified": "2023-02-17T00:02:54.348Z" - }, - { - "x": 2, - "y": 345, - "type": "TEXT", - "value": "Syracuse-Hamilton County Municipal", - "last_modified": "2023-02-17T00:02:54.349Z" - }, - { - "x": 3, - "y": 345, - "type": "TEXT", - "value": "Syracuse", - "last_modified": "2023-02-17T00:02:54.351Z" - }, - { - "x": 4, - "y": 345, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:54.353Z" - }, - { - "x": 5, - "y": 345, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.354Z" - }, - { - "x": 6, - "y": 345, - "type": "TEXT", - "value": "37.99167972", - "last_modified": "2023-02-17T00:02:54.356Z" - }, - { - "x": 7, - "y": 345, - "type": "TEXT", - "value": "-101.7462822", - "last_modified": "2023-02-17T00:02:54.358Z" - }, - { - "x": 0, - "y": 346, - "type": "TEXT", - "value": "343", - "last_modified": "2023-02-17T00:02:54.359Z" - }, - { - "x": 1, - "y": 346, - "type": "TEXT", - "value": "3K6", - "last_modified": "2023-02-17T00:02:54.361Z" - }, - { - "x": 2, - "y": 346, - "type": "TEXT", - "value": "St Louis-Metro East", - "last_modified": "2023-02-17T00:02:54.363Z" - }, - { - "x": 3, - "y": 346, - "type": "TEXT", - "value": "Troy/Marine/St. Louis", - "last_modified": "2023-02-17T00:02:54.364Z" - }, - { - "x": 4, - "y": 346, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:54.366Z" - }, - { - "x": 5, - "y": 346, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.368Z" - }, - { - "x": 6, - "y": 346, - "type": "TEXT", - "value": "38.73290861", - "last_modified": "2023-02-17T00:02:54.369Z" - }, - { - "x": 7, - "y": 346, - "type": "TEXT", - "value": "-89.80656722", - "last_modified": "2023-02-17T00:02:54.371Z" - }, - { - "x": 0, - "y": 347, - "type": "TEXT", - "value": "344", - "last_modified": "2023-02-17T00:02:54.373Z" - }, - { - "x": 1, - "y": 347, - "type": "TEXT", - "value": "3K7", - "last_modified": "2023-02-17T00:02:54.374Z" - }, - { - "x": 2, - "y": 347, - "type": "TEXT", - "value": "Mark Hoard Memorial", - "last_modified": "2023-02-17T00:02:54.376Z" - }, - { - "x": 3, - "y": 347, - "type": "TEXT", - "value": "Leoti", - "last_modified": "2023-02-17T00:02:54.378Z" - }, - { - "x": 4, - "y": 347, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:54.379Z" - }, - { - "x": 5, - "y": 347, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.381Z" - }, - { - "x": 6, - "y": 347, - "type": "TEXT", - "value": "38.45696333", - "last_modified": "2023-02-17T00:02:54.383Z" - }, - { - "x": 7, - "y": 347, - "type": "TEXT", - "value": "-101.3532161", - "last_modified": "2023-02-17T00:02:54.384Z" - }, - { - "x": 0, - "y": 348, - "type": "TEXT", - "value": "345", - "last_modified": "2023-02-17T00:02:54.386Z" - }, - { - "x": 1, - "y": 348, - "type": "TEXT", - "value": "3LC", - "last_modified": "2023-02-17T00:02:54.387Z" - }, - { - "x": 2, - "y": 348, - "type": "TEXT", - "value": "Logan County", - "last_modified": "2023-02-17T00:02:54.389Z" - }, - { - "x": 3, - "y": 348, - "type": "TEXT", - "value": "Lincoln", - "last_modified": "2023-02-17T00:02:54.391Z" - }, - { - "x": 4, - "y": 348, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:54.392Z" - }, - { - "x": 5, - "y": 348, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.394Z" - }, - { - "x": 6, - "y": 348, - "type": "TEXT", - "value": "40.15847222", - "last_modified": "2023-02-17T00:02:54.396Z" - }, - { - "x": 7, - "y": 348, - "type": "TEXT", - "value": "-89.33497222", - "last_modified": "2023-02-17T00:02:54.397Z" - }, - { - "x": 0, - "y": 349, - "type": "TEXT", - "value": "346", - "last_modified": "2023-02-17T00:02:54.399Z" - }, - { - "x": 1, - "y": 349, - "type": "TEXT", - "value": "3LF", - "last_modified": "2023-02-17T00:02:54.400Z" - }, - { - "x": 2, - "y": 349, - "type": "TEXT", - "value": "Litchfield Municipal", - "last_modified": "2023-02-17T00:02:54.402Z" - }, - { - "x": 3, - "y": 349, - "type": "TEXT", - "value": "Litchfield", - "last_modified": "2023-02-17T00:02:54.404Z" - }, - { - "x": 4, - "y": 349, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:54.405Z" - }, - { - "x": 5, - "y": 349, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.407Z" - }, - { - "x": 6, - "y": 349, - "type": "TEXT", - "value": "39.16635306", - "last_modified": "2023-02-17T00:02:54.409Z" - }, - { - "x": 7, - "y": 349, - "type": "TEXT", - "value": "-89.67489694", - "last_modified": "2023-02-17T00:02:54.410Z" - }, - { - "x": 0, - "y": 350, - "type": "TEXT", - "value": "347", - "last_modified": "2023-02-17T00:02:54.412Z" - }, - { - "x": 1, - "y": 350, - "type": "TEXT", - "value": "3M7", - "last_modified": "2023-02-17T00:02:54.414Z" - }, - { - "x": 2, - "y": 350, - "type": "TEXT", - "value": "Lafayette Municipal", - "last_modified": "2023-02-17T00:02:54.415Z" - }, - { - "x": 3, - "y": 350, - "type": "TEXT", - "value": "Lafayette", - "last_modified": "2023-02-17T00:02:54.417Z" - }, - { - "x": 4, - "y": 350, - "type": "TEXT", - "value": "TN", - "last_modified": "2023-02-17T00:02:54.418Z" - }, - { - "x": 5, - "y": 350, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.420Z" - }, - { - "x": 6, - "y": 350, - "type": "TEXT", - "value": "36.518375", - "last_modified": "2023-02-17T00:02:54.422Z" - }, - { - "x": 7, - "y": 350, - "type": "TEXT", - "value": "-86.05828083", - "last_modified": "2023-02-17T00:02:54.423Z" - }, - { - "x": 0, - "y": 351, - "type": "TEXT", - "value": "348", - "last_modified": "2023-02-17T00:02:54.425Z" - }, - { - "x": 1, - "y": 351, - "type": "TEXT", - "value": "3M8", - "last_modified": "2023-02-17T00:02:54.426Z" - }, - { - "x": 2, - "y": 351, - "type": "TEXT", - "value": "North Pickens", - "last_modified": "2023-02-17T00:02:54.428Z" - }, - { - "x": 3, - "y": 351, - "type": "TEXT", - "value": "Reform", - "last_modified": "2023-02-17T00:02:54.429Z" - }, - { - "x": 4, - "y": 351, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:54.431Z" - }, - { - "x": 5, - "y": 351, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.433Z" - }, - { - "x": 6, - "y": 351, - "type": "TEXT", - "value": "33.38900611", - "last_modified": "2023-02-17T00:02:54.434Z" - }, - { - "x": 7, - "y": 351, - "type": "TEXT", - "value": "-88.00557806", - "last_modified": "2023-02-17T00:02:54.436Z" - }, - { - "x": 0, - "y": 352, - "type": "TEXT", - "value": "349", - "last_modified": "2023-02-17T00:02:54.437Z" - }, - { - "x": 1, - "y": 352, - "type": "TEXT", - "value": "3M9", - "last_modified": "2023-02-17T00:02:54.439Z" - }, - { - "x": 2, - "y": 352, - "type": "TEXT", - "value": "Warren Municipal", - "last_modified": "2023-02-17T00:02:54.440Z" - }, - { - "x": 3, - "y": 352, - "type": "TEXT", - "value": "Warren", - "last_modified": "2023-02-17T00:02:54.442Z" - }, - { - "x": 4, - "y": 352, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:54.444Z" - }, - { - "x": 5, - "y": 352, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.445Z" - }, - { - "x": 6, - "y": 352, - "type": "TEXT", - "value": "33.56044333", - "last_modified": "2023-02-17T00:02:54.447Z" - }, - { - "x": 7, - "y": 352, - "type": "TEXT", - "value": "-92.08538861", - "last_modified": "2023-02-17T00:02:54.448Z" - }, - { - "x": 0, - "y": 353, - "type": "TEXT", - "value": "350", - "last_modified": "2023-02-17T00:02:54.450Z" - }, - { - "x": 1, - "y": 353, - "type": "TEXT", - "value": "3MY", - "last_modified": "2023-02-17T00:02:54.451Z" - }, - { - "x": 2, - "y": 353, - "type": "TEXT", - "value": "Mt. Hawley Auxiliary", - "last_modified": "2023-02-17T00:02:54.453Z" - }, - { - "x": 3, - "y": 353, - "type": "TEXT", - "value": "Peoria", - "last_modified": "2023-02-17T00:02:54.454Z" - }, - { - "x": 4, - "y": 353, - "type": "TEXT", - "value": "IL", - "last_modified": "2023-02-17T00:02:54.456Z" - }, - { - "x": 5, - "y": 353, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.457Z" - }, - { - "x": 6, - "y": 353, - "type": "TEXT", - "value": "40.79525917", - "last_modified": "2023-02-17T00:02:54.459Z" - }, - { - "x": 7, - "y": 353, - "type": "TEXT", - "value": "-89.6134025", - "last_modified": "2023-02-17T00:02:54.460Z" - }, - { - "x": 0, - "y": 354, - "type": "TEXT", - "value": "351", - "last_modified": "2023-02-17T00:02:54.462Z" - }, - { - "x": 1, - "y": 354, - "type": "TEXT", - "value": "3N6", - "last_modified": "2023-02-17T00:02:54.464Z" - }, - { - "x": 2, - "y": 354, - "type": "TEXT", - "value": "Old Bridge", - "last_modified": "2023-02-17T00:02:54.465Z" - }, - { - "x": 3, - "y": 354, - "type": "TEXT", - "value": "Old Bridge", - "last_modified": "2023-02-17T00:02:54.467Z" - }, - { - "x": 4, - "y": 354, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:54.468Z" - }, - { - "x": 5, - "y": 354, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.470Z" - }, - { - "x": 6, - "y": 354, - "type": "TEXT", - "value": "40.32988667", - "last_modified": "2023-02-17T00:02:54.471Z" - }, - { - "x": 7, - "y": 354, - "type": "TEXT", - "value": "-74.34678694", - "last_modified": "2023-02-17T00:02:54.473Z" - }, - { - "x": 0, - "y": 355, - "type": "TEXT", - "value": "352", - "last_modified": "2023-02-17T00:02:54.474Z" - }, - { - "x": 1, - "y": 355, - "type": "TEXT", - "value": "3N8", - "last_modified": "2023-02-17T00:02:54.476Z" - }, - { - "x": 2, - "y": 355, - "type": "TEXT", - "value": "Mahnomen County", - "last_modified": "2023-02-17T00:02:54.477Z" - }, - { - "x": 3, - "y": 355, - "type": "TEXT", - "value": "Mahnomen", - "last_modified": "2023-02-17T00:02:54.479Z" - }, - { - "x": 4, - "y": 355, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:54.480Z" - }, - { - "x": 5, - "y": 355, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.482Z" - }, - { - "x": 6, - "y": 355, - "type": "TEXT", - "value": "47.25996056", - "last_modified": "2023-02-17T00:02:54.483Z" - }, - { - "x": 7, - "y": 355, - "type": "TEXT", - "value": "-95.92809778", - "last_modified": "2023-02-17T00:02:54.485Z" - }, - { - "x": 0, - "y": 356, - "type": "TEXT", - "value": "353", - "last_modified": "2023-02-17T00:02:54.486Z" - }, - { - "x": 1, - "y": 356, - "type": "TEXT", - "value": "3ND0", - "last_modified": "2023-02-17T00:02:54.488Z" - }, - { - "x": 2, - "y": 356, - "type": "TEXT", - "value": "Northwood Municipal", - "last_modified": "2023-02-17T00:02:54.489Z" - }, - { - "x": 3, - "y": 356, - "type": "TEXT", - "value": "Northwood", - "last_modified": "2023-02-17T00:02:54.491Z" - }, - { - "x": 4, - "y": 356, - "type": "TEXT", - "value": "ND", - "last_modified": "2023-02-17T00:02:54.492Z" - }, - { - "x": 5, - "y": 356, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.494Z" - }, - { - "x": 6, - "y": 356, - "type": "TEXT", - "value": "47.72423333", - "last_modified": "2023-02-17T00:02:54.495Z" - }, - { - "x": 7, - "y": 356, - "type": "TEXT", - "value": "-97.59042222", - "last_modified": "2023-02-17T00:02:54.496Z" - }, - { - "x": 0, - "y": 357, - "type": "TEXT", - "value": "354", - "last_modified": "2023-02-17T00:02:54.498Z" - }, - { - "x": 1, - "y": 357, - "type": "TEXT", - "value": "3O1", - "last_modified": "2023-02-17T00:02:54.499Z" - }, - { - "x": 2, - "y": 357, - "type": "TEXT", - "value": "Gustine", - "last_modified": "2023-02-17T00:02:54.501Z" - }, - { - "x": 3, - "y": 357, - "type": "TEXT", - "value": "Gustine", - "last_modified": "2023-02-17T00:02:54.502Z" - }, - { - "x": 4, - "y": 357, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:54.504Z" - }, - { - "x": 5, - "y": 357, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.505Z" - }, - { - "x": 6, - "y": 357, - "type": "TEXT", - "value": "37.26271722", - "last_modified": "2023-02-17T00:02:54.507Z" - }, - { - "x": 7, - "y": 357, - "type": "TEXT", - "value": "-120.9632586", - "last_modified": "2023-02-17T00:02:54.508Z" - }, - { - "x": 0, - "y": 358, - "type": "TEXT", - "value": "355", - "last_modified": "2023-02-17T00:02:54.510Z" - }, - { - "x": 1, - "y": 358, - "type": "TEXT", - "value": "3O3", - "last_modified": "2023-02-17T00:02:54.511Z" - }, - { - "x": 2, - "y": 358, - "type": "TEXT", - "value": "Municipal", - "last_modified": "2023-02-17T00:02:54.513Z" - }, - { - "x": 3, - "y": 358, - "type": "TEXT", - "value": "Purcell", - "last_modified": "2023-02-17T00:02:54.514Z" - }, - { - "x": 4, - "y": 358, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:54.516Z" - }, - { - "x": 5, - "y": 358, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.517Z" - }, - { - "x": 6, - "y": 358, - "type": "TEXT", - "value": "34.97979444", - "last_modified": "2023-02-17T00:02:54.518Z" - }, - { - "x": 7, - "y": 358, - "type": "TEXT", - "value": "-97.38586167", - "last_modified": "2023-02-17T00:02:54.520Z" - }, - { - "x": 0, - "y": 359, - "type": "TEXT", - "value": "356", - "last_modified": "2023-02-17T00:02:54.521Z" - }, - { - "x": 1, - "y": 359, - "type": "TEXT", - "value": "3O4", - "last_modified": "2023-02-17T00:02:54.523Z" - }, - { - "x": 2, - "y": 359, - "type": "TEXT", - "value": "Sayre Municipal", - "last_modified": "2023-02-17T00:02:54.524Z" - }, - { - "x": 3, - "y": 359, - "type": "TEXT", - "value": "Sayre", - "last_modified": "2023-02-17T00:02:54.526Z" - }, - { - "x": 4, - "y": 359, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:54.527Z" - }, - { - "x": 5, - "y": 359, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.528Z" - }, - { - "x": 6, - "y": 359, - "type": "TEXT", - "value": "35.16755222", - "last_modified": "2023-02-17T00:02:54.530Z" - }, - { - "x": 7, - "y": 359, - "type": "TEXT", - "value": "-99.65787361", - "last_modified": "2023-02-17T00:02:54.531Z" - }, - { - "x": 0, - "y": 360, - "type": "TEXT", - "value": "357", - "last_modified": "2023-02-17T00:02:54.533Z" - }, - { - "x": 1, - "y": 360, - "type": "TEXT", - "value": "3O5", - "last_modified": "2023-02-17T00:02:54.534Z" - }, - { - "x": 2, - "y": 360, - "type": "TEXT", - "value": "Walters Municipal", - "last_modified": "2023-02-17T00:02:54.536Z" - }, - { - "x": 3, - "y": 360, - "type": "TEXT", - "value": "Walters", - "last_modified": "2023-02-17T00:02:54.537Z" - }, - { - "x": 4, - "y": 360, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:54.538Z" - }, - { - "x": 5, - "y": 360, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.540Z" - }, - { - "x": 6, - "y": 360, - "type": "TEXT", - "value": "34.37258444", - "last_modified": "2023-02-17T00:02:54.541Z" - }, - { - "x": 7, - "y": 360, - "type": "TEXT", - "value": "-98.40588583", - "last_modified": "2023-02-17T00:02:54.543Z" - }, - { - "x": 0, - "y": 361, - "type": "TEXT", - "value": "358", - "last_modified": "2023-02-17T00:02:54.544Z" - }, - { - "x": 1, - "y": 361, - "type": "TEXT", - "value": "3O7", - "last_modified": "2023-02-17T00:02:54.545Z" - }, - { - "x": 2, - "y": 361, - "type": "TEXT", - "value": "Hollister Municipal", - "last_modified": "2023-02-17T00:02:54.547Z" - }, - { - "x": 3, - "y": 361, - "type": "TEXT", - "value": "Hollister", - "last_modified": "2023-02-17T00:02:54.548Z" - }, - { - "x": 4, - "y": 361, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:54.550Z" - }, - { - "x": 5, - "y": 361, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.551Z" - }, - { - "x": 6, - "y": 361, - "type": "TEXT", - "value": "36.89334528", - "last_modified": "2023-02-17T00:02:54.552Z" - }, - { - "x": 7, - "y": 361, - "type": "TEXT", - "value": "-121.4102706", - "last_modified": "2023-02-17T00:02:54.554Z" - }, - { - "x": 0, - "y": 362, - "type": "TEXT", - "value": "359", - "last_modified": "2023-02-17T00:02:54.555Z" - }, - { - "x": 1, - "y": 362, - "type": "TEXT", - "value": "3O9", - "last_modified": "2023-02-17T00:02:54.556Z" - }, - { - "x": 2, - "y": 362, - "type": "TEXT", - "value": "Grand Lake Regional", - "last_modified": "2023-02-17T00:02:54.558Z" - }, - { - "x": 3, - "y": 362, - "type": "TEXT", - "value": "Afton", - "last_modified": "2023-02-17T00:02:54.559Z" - }, - { - "x": 4, - "y": 362, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:54.561Z" - }, - { - "x": 5, - "y": 362, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.562Z" - }, - { - "x": 6, - "y": 362, - "type": "TEXT", - "value": "36.5775775", - "last_modified": "2023-02-17T00:02:54.563Z" - }, - { - "x": 7, - "y": 362, - "type": "TEXT", - "value": "-94.86190028", - "last_modified": "2023-02-17T00:02:54.565Z" - }, - { - "x": 0, - "y": 363, - "type": "TEXT", - "value": "360", - "last_modified": "2023-02-17T00:02:54.566Z" - }, - { - "x": 1, - "y": 363, - "type": "TEXT", - "value": "3R0", - "last_modified": "2023-02-17T00:02:54.567Z" - }, - { - "x": 2, - "y": 363, - "type": "TEXT", - "value": "Beeville Municipal", - "last_modified": "2023-02-17T00:02:54.569Z" - }, - { - "x": 3, - "y": 363, - "type": "TEXT", - "value": "Beeville", - "last_modified": "2023-02-17T00:02:54.570Z" - }, - { - "x": 4, - "y": 363, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:54.572Z" - }, - { - "x": 5, - "y": 363, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.573Z" - }, - { - "x": 6, - "y": 363, - "type": "TEXT", - "value": "28.36455528", - "last_modified": "2023-02-17T00:02:54.574Z" - }, - { - "x": 7, - "y": 363, - "type": "TEXT", - "value": "-97.79208194", - "last_modified": "2023-02-17T00:02:54.576Z" - }, - { - "x": 0, - "y": 364, - "type": "TEXT", - "value": "361", - "last_modified": "2023-02-17T00:02:54.577Z" - }, - { - "x": 1, - "y": 364, - "type": "TEXT", - "value": "3R1", - "last_modified": "2023-02-17T00:02:54.578Z" - }, - { - "x": 2, - "y": 364, - "type": "TEXT", - "value": "Bay City Municipal", - "last_modified": "2023-02-17T00:02:54.580Z" - }, - { - "x": 3, - "y": 364, - "type": "TEXT", - "value": "Bay City", - "last_modified": "2023-02-17T00:02:54.581Z" - }, - { - "x": 4, - "y": 364, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:54.582Z" - }, - { - "x": 5, - "y": 364, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.584Z" - }, - { - "x": 6, - "y": 364, - "type": "TEXT", - "value": "28.973255", - "last_modified": "2023-02-17T00:02:54.585Z" - }, - { - "x": 7, - "y": 364, - "type": "TEXT", - "value": "-95.86345528", - "last_modified": "2023-02-17T00:02:54.586Z" - }, - { - "x": 0, - "y": 365, - "type": "TEXT", - "value": "362", - "last_modified": "2023-02-17T00:02:54.588Z" - }, - { - "x": 1, - "y": 365, - "type": "TEXT", - "value": "3R2", - "last_modified": "2023-02-17T00:02:54.589Z" - }, - { - "x": 2, - "y": 365, - "type": "TEXT", - "value": "Le Gros Memorial", - "last_modified": "2023-02-17T00:02:54.590Z" - }, - { - "x": 3, - "y": 365, - "type": "TEXT", - "value": "Crowley", - "last_modified": "2023-02-17T00:02:54.592Z" - }, - { - "x": 4, - "y": 365, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:54.593Z" - }, - { - "x": 5, - "y": 365, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.594Z" - }, - { - "x": 6, - "y": 365, - "type": "TEXT", - "value": "30.16173611", - "last_modified": "2023-02-17T00:02:54.596Z" - }, - { - "x": 7, - "y": 365, - "type": "TEXT", - "value": "-92.48396111", - "last_modified": "2023-02-17T00:02:54.597Z" - }, - { - "x": 0, - "y": 366, - "type": "TEXT", - "value": "363", - "last_modified": "2023-02-17T00:02:54.598Z" - }, - { - "x": 1, - "y": 366, - "type": "TEXT", - "value": "3R4", - "last_modified": "2023-02-17T00:02:54.600Z" - }, - { - "x": 2, - "y": 366, - "type": "TEXT", - "value": "Hart", - "last_modified": "2023-02-17T00:02:54.601Z" - }, - { - "x": 3, - "y": 366, - "type": "TEXT", - "value": "Many", - "last_modified": "2023-02-17T00:02:54.602Z" - }, - { - "x": 4, - "y": 366, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:54.604Z" - }, - { - "x": 5, - "y": 366, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.605Z" - }, - { - "x": 6, - "y": 366, - "type": "TEXT", - "value": "31.54489667", - "last_modified": "2023-02-17T00:02:54.606Z" - }, - { - "x": 7, - "y": 366, - "type": "TEXT", - "value": "-93.48645306", - "last_modified": "2023-02-17T00:02:54.608Z" - }, - { - "x": 0, - "y": 367, - "type": "TEXT", - "value": "364", - "last_modified": "2023-02-17T00:02:54.609Z" - }, - { - "x": 1, - "y": 367, - "type": "TEXT", - "value": "3R7", - "last_modified": "2023-02-17T00:02:54.610Z" - }, - { - "x": 2, - "y": 367, - "type": "TEXT", - "value": "Jennings", - "last_modified": "2023-02-17T00:02:54.611Z" - }, - { - "x": 3, - "y": 367, - "type": "TEXT", - "value": "Jennings", - "last_modified": "2023-02-17T00:02:54.613Z" - }, - { - "x": 4, - "y": 367, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:54.614Z" - }, - { - "x": 5, - "y": 367, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.615Z" - }, - { - "x": 6, - "y": 367, - "type": "TEXT", - "value": "30.24269333", - "last_modified": "2023-02-17T00:02:54.617Z" - }, - { - "x": 7, - "y": 367, - "type": "TEXT", - "value": "-92.67344778", - "last_modified": "2023-02-17T00:02:54.618Z" - }, - { - "x": 0, - "y": 368, - "type": "TEXT", - "value": "365", - "last_modified": "2023-02-17T00:02:54.619Z" - }, - { - "x": 1, - "y": 368, - "type": "TEXT", - "value": "3S4", - "last_modified": "2023-02-17T00:02:54.620Z" - }, - { - "x": 2, - "y": 368, - "type": "TEXT", - "value": "Illinois Valley", - "last_modified": "2023-02-17T00:02:54.622Z" - }, - { - "x": 3, - "y": 368, - "type": "TEXT", - "value": "Illinois Valley (Cave Junction)", - "last_modified": "2023-02-17T00:02:54.623Z" - }, - { - "x": 4, - "y": 368, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:54.624Z" - }, - { - "x": 5, - "y": 368, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.626Z" - }, - { - "x": 6, - "y": 368, - "type": "TEXT", - "value": "42.10372417", - "last_modified": "2023-02-17T00:02:54.627Z" - }, - { - "x": 7, - "y": 368, - "type": "TEXT", - "value": "-123.6822911", - "last_modified": "2023-02-17T00:02:54.628Z" - }, - { - "x": 0, - "y": 369, - "type": "TEXT", - "value": "366", - "last_modified": "2023-02-17T00:02:54.629Z" - }, - { - "x": 1, - "y": 369, - "type": "TEXT", - "value": "3S8", - "last_modified": "2023-02-17T00:02:54.631Z" - }, - { - "x": 2, - "y": 369, - "type": "TEXT", - "value": "Grants Pass", - "last_modified": "2023-02-17T00:02:54.632Z" - }, - { - "x": 3, - "y": 369, - "type": "TEXT", - "value": "Grants Pass", - "last_modified": "2023-02-17T00:02:54.633Z" - }, - { - "x": 4, - "y": 369, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:54.634Z" - }, - { - "x": 5, - "y": 369, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.636Z" - }, - { - "x": 6, - "y": 369, - "type": "TEXT", - "value": "42.51011722", - "last_modified": "2023-02-17T00:02:54.637Z" - }, - { - "x": 7, - "y": 369, - "type": "TEXT", - "value": "-123.3879894", - "last_modified": "2023-02-17T00:02:54.638Z" - }, - { - "x": 0, - "y": 370, - "type": "TEXT", - "value": "367", - "last_modified": "2023-02-17T00:02:54.639Z" - }, - { - "x": 1, - "y": 370, - "type": "TEXT", - "value": "3S9", - "last_modified": "2023-02-17T00:02:54.641Z" - }, - { - "x": 2, - "y": 370, - "type": "TEXT", - "value": "Condon State-Pauling", - "last_modified": "2023-02-17T00:02:54.642Z" - }, - { - "x": 3, - "y": 370, - "type": "TEXT", - "value": "Condon", - "last_modified": "2023-02-17T00:02:54.643Z" - }, - { - "x": 4, - "y": 370, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:54.644Z" - }, - { - "x": 5, - "y": 370, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.646Z" - }, - { - "x": 6, - "y": 370, - "type": "TEXT", - "value": "45.24651889", - "last_modified": "2023-02-17T00:02:54.647Z" - }, - { - "x": 7, - "y": 370, - "type": "TEXT", - "value": "-120.1664233", - "last_modified": "2023-02-17T00:02:54.648Z" - }, - { - "x": 0, - "y": 371, - "type": "TEXT", - "value": "368", - "last_modified": "2023-02-17T00:02:54.649Z" - }, - { - "x": 1, - "y": 371, - "type": "TEXT", - "value": "3SG", - "last_modified": "2023-02-17T00:02:54.650Z" - }, - { - "x": 2, - "y": 371, - "type": "TEXT", - "value": "Harry W Browne", - "last_modified": "2023-02-17T00:02:54.652Z" - }, - { - "x": 3, - "y": 371, - "type": "TEXT", - "value": "Saginaw - H.Browne", - "last_modified": "2023-02-17T00:02:54.653Z" - }, - { - "x": 4, - "y": 371, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:54.654Z" - }, - { - "x": 5, - "y": 371, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.655Z" - }, - { - "x": 6, - "y": 371, - "type": "TEXT", - "value": "43.43341028", - "last_modified": "2023-02-17T00:02:54.657Z" - }, - { - "x": 7, - "y": 371, - "type": "TEXT", - "value": "-83.86245833", - "last_modified": "2023-02-17T00:02:54.658Z" - }, - { - "x": 0, - "y": 372, - "type": "TEXT", - "value": "369", - "last_modified": "2023-02-17T00:02:54.659Z" - }, - { - "x": 1, - "y": 372, - "type": "TEXT", - "value": "3SQ", - "last_modified": "2023-02-17T00:02:54.660Z" - }, - { - "x": 2, - "y": 372, - "type": "TEXT", - "value": "St Charles", - "last_modified": "2023-02-17T00:02:54.661Z" - }, - { - "x": 3, - "y": 372, - "type": "TEXT", - "value": "St Charles", - "last_modified": "2023-02-17T00:02:54.663Z" - }, - { - "x": 4, - "y": 372, - "type": "TEXT", - "value": "MO", - "last_modified": "2023-02-17T00:02:54.664Z" - }, - { - "x": 5, - "y": 372, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.665Z" - }, - { - "x": 6, - "y": 372, - "type": "TEXT", - "value": "38.84866139", - "last_modified": "2023-02-17T00:02:54.666Z" - }, - { - "x": 7, - "y": 372, - "type": "TEXT", - "value": "-90.50011833", - "last_modified": "2023-02-17T00:02:54.667Z" - }, - { - "x": 0, - "y": 373, - "type": "TEXT", - "value": "370", - "last_modified": "2023-02-17T00:02:54.669Z" - }, - { - "x": 1, - "y": 373, - "type": "TEXT", - "value": "3T3", - "last_modified": "2023-02-17T00:02:54.670Z" - }, - { - "x": 2, - "y": 373, - "type": "TEXT", - "value": "Boyceville Municipal", - "last_modified": "2023-02-17T00:02:54.671Z" - }, - { - "x": 3, - "y": 373, - "type": "TEXT", - "value": "Boyceville", - "last_modified": "2023-02-17T00:02:54.672Z" - }, - { - "x": 4, - "y": 373, - "type": "TEXT", - "value": "WI", - "last_modified": "2023-02-17T00:02:54.673Z" - }, - { - "x": 5, - "y": 373, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.675Z" - }, - { - "x": 6, - "y": 373, - "type": "TEXT", - "value": "45.042185", - "last_modified": "2023-02-17T00:02:54.676Z" - }, - { - "x": 7, - "y": 373, - "type": "TEXT", - "value": "-92.0293475", - "last_modified": "2023-02-17T00:02:54.677Z" - }, - { - "x": 0, - "y": 374, - "type": "TEXT", - "value": "371", - "last_modified": "2023-02-17T00:02:54.678Z" - }, - { - "x": 1, - "y": 374, - "type": "TEXT", - "value": "3T5", - "last_modified": "2023-02-17T00:02:54.679Z" - }, - { - "x": 2, - "y": 374, - "type": "TEXT", - "value": "Fayette Regional Air Center", - "last_modified": "2023-02-17T00:02:54.681Z" - }, - { - "x": 3, - "y": 374, - "type": "TEXT", - "value": "La Grange", - "last_modified": "2023-02-17T00:02:54.682Z" - }, - { - "x": 4, - "y": 374, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:54.683Z" - }, - { - "x": 5, - "y": 374, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.684Z" - }, - { - "x": 6, - "y": 374, - "type": "TEXT", - "value": "29.90930556", - "last_modified": "2023-02-17T00:02:54.685Z" - }, - { - "x": 7, - "y": 374, - "type": "TEXT", - "value": "-96.9505", - "last_modified": "2023-02-17T00:02:54.686Z" - }, - { - "x": 0, - "y": 375, - "type": "TEXT", - "value": "372", - "last_modified": "2023-02-17T00:02:54.688Z" - }, - { - "x": 1, - "y": 375, - "type": "TEXT", - "value": "3TR", - "last_modified": "2023-02-17T00:02:54.689Z" - }, - { - "x": 2, - "y": 375, - "type": "TEXT", - "value": "Jerry Tyler Memorial", - "last_modified": "2023-02-17T00:02:54.690Z" - }, - { - "x": 3, - "y": 375, - "type": "TEXT", - "value": "Niles", - "last_modified": "2023-02-17T00:02:54.691Z" - }, - { - "x": 4, - "y": 375, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:54.692Z" - }, - { - "x": 5, - "y": 375, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.693Z" - }, - { - "x": 6, - "y": 375, - "type": "TEXT", - "value": "41.83590806", - "last_modified": "2023-02-17T00:02:54.695Z" - }, - { - "x": 7, - "y": 375, - "type": "TEXT", - "value": "-86.22517611", - "last_modified": "2023-02-17T00:02:54.696Z" - }, - { - "x": 0, - "y": 376, - "type": "TEXT", - "value": "373", - "last_modified": "2023-02-17T00:02:54.697Z" - }, - { - "x": 1, - "y": 376, - "type": "TEXT", - "value": "3U3", - "last_modified": "2023-02-17T00:02:54.698Z" - }, - { - "x": 2, - "y": 376, - "type": "TEXT", - "value": "Bowman", - "last_modified": "2023-02-17T00:02:54.699Z" - }, - { - "x": 3, - "y": 376, - "type": "TEXT", - "value": "Anaconda", - "last_modified": "2023-02-17T00:02:54.700Z" - }, - { - "x": 4, - "y": 376, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:54.701Z" - }, - { - "x": 5, - "y": 376, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.703Z" - }, - { - "x": 6, - "y": 376, - "type": "TEXT", - "value": "46.15313278", - "last_modified": "2023-02-17T00:02:54.704Z" - }, - { - "x": 7, - "y": 376, - "type": "TEXT", - "value": "-112.86784", - "last_modified": "2023-02-17T00:02:54.705Z" - }, - { - "x": 0, - "y": 377, - "type": "TEXT", - "value": "374", - "last_modified": "2023-02-17T00:02:54.706Z" - }, - { - "x": 1, - "y": 377, - "type": "TEXT", - "value": "3U7", - "last_modified": "2023-02-17T00:02:54.707Z" - }, - { - "x": 2, - "y": 377, - "type": "TEXT", - "value": "Benchmark", - "last_modified": "2023-02-17T00:02:54.708Z" - }, - { - "x": 3, - "y": 377, - "type": "TEXT", - "value": "Benchmark", - "last_modified": "2023-02-17T00:02:54.709Z" - }, - { - "x": 4, - "y": 377, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:54.711Z" - }, - { - "x": 5, - "y": 377, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.712Z" - }, - { - "x": 6, - "y": 377, - "type": "TEXT", - "value": "47.48133194", - "last_modified": "2023-02-17T00:02:54.713Z" - }, - { - "x": 7, - "y": 377, - "type": "TEXT", - "value": "-112.8697678", - "last_modified": "2023-02-17T00:02:54.714Z" - }, - { - "x": 0, - "y": 378, - "type": "TEXT", - "value": "375", - "last_modified": "2023-02-17T00:02:54.715Z" - }, - { - "x": 1, - "y": 378, - "type": "TEXT", - "value": "3U8", - "last_modified": "2023-02-17T00:02:54.716Z" - }, - { - "x": 2, - "y": 378, - "type": "TEXT", - "value": "Big Sandy", - "last_modified": "2023-02-17T00:02:54.717Z" - }, - { - "x": 3, - "y": 378, - "type": "TEXT", - "value": "Big Sandy", - "last_modified": "2023-02-17T00:02:54.718Z" - }, - { - "x": 4, - "y": 378, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:54.720Z" - }, - { - "x": 5, - "y": 378, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.721Z" - }, - { - "x": 6, - "y": 378, - "type": "TEXT", - "value": "48.16247972", - "last_modified": "2023-02-17T00:02:54.722Z" - }, - { - "x": 7, - "y": 378, - "type": "TEXT", - "value": "-110.1132631", - "last_modified": "2023-02-17T00:02:54.723Z" - }, - { - "x": 0, - "y": 379, - "type": "TEXT", - "value": "376", - "last_modified": "2023-02-17T00:02:54.724Z" - }, - { - "x": 1, - "y": 379, - "type": "TEXT", - "value": "3V4", - "last_modified": "2023-02-17T00:02:54.725Z" - }, - { - "x": 2, - "y": 379, - "type": "TEXT", - "value": "Fort Morgan Municipal", - "last_modified": "2023-02-17T00:02:54.726Z" - }, - { - "x": 3, - "y": 379, - "type": "TEXT", - "value": "Fort Morgan", - "last_modified": "2023-02-17T00:02:54.727Z" - }, - { - "x": 4, - "y": 379, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:54.728Z" - }, - { - "x": 5, - "y": 379, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.729Z" - }, - { - "x": 6, - "y": 379, - "type": "TEXT", - "value": "40.33423194", - "last_modified": "2023-02-17T00:02:54.731Z" - }, - { - "x": 7, - "y": 379, - "type": "TEXT", - "value": "-103.8039508", - "last_modified": "2023-02-17T00:02:54.732Z" - }, - { - "x": 0, - "y": 380, - "type": "TEXT", - "value": "377", - "last_modified": "2023-02-17T00:02:54.733Z" - }, - { - "x": 1, - "y": 380, - "type": "TEXT", - "value": "3WO", - "last_modified": "2023-02-17T00:02:54.734Z" - }, - { - "x": 2, - "y": 380, - "type": "TEXT", - "value": "Shawano Municipal", - "last_modified": "2023-02-17T00:02:54.735Z" - }, - { - "x": 3, - "y": 380, - "type": "TEXT", - "value": "Shawano", - "last_modified": "2023-02-17T00:02:54.736Z" - }, - { - "x": 4, - "y": 380, - "type": "TEXT", - "value": "WI", - "last_modified": "2023-02-17T00:02:54.737Z" - }, - { - "x": 5, - "y": 380, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.738Z" - }, - { - "x": 6, - "y": 380, - "type": "TEXT", - "value": "44.78777778", - "last_modified": "2023-02-17T00:02:54.739Z" - }, - { - "x": 7, - "y": 380, - "type": "TEXT", - "value": "-88.56152444", - "last_modified": "2023-02-17T00:02:54.740Z" - }, - { - "x": 0, - "y": 381, - "type": "TEXT", - "value": "378", - "last_modified": "2023-02-17T00:02:54.741Z" - }, - { - "x": 1, - "y": 381, - "type": "TEXT", - "value": "3Y2", - "last_modified": "2023-02-17T00:02:54.742Z" - }, - { - "x": 2, - "y": 381, - "type": "TEXT", - "value": "George L Scott Municipal", - "last_modified": "2023-02-17T00:02:54.744Z" - }, - { - "x": 3, - "y": 381, - "type": "TEXT", - "value": "West Union", - "last_modified": "2023-02-17T00:02:54.745Z" - }, - { - "x": 4, - "y": 381, - "type": "TEXT", - "value": "IA", - "last_modified": "2023-02-17T00:02:54.746Z" - }, - { - "x": 5, - "y": 381, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.747Z" - }, - { - "x": 6, - "y": 381, - "type": "TEXT", - "value": "42.98508917", - "last_modified": "2023-02-17T00:02:54.748Z" - }, - { - "x": 7, - "y": 381, - "type": "TEXT", - "value": "-91.79060417", - "last_modified": "2023-02-17T00:02:54.749Z" - }, - { - "x": 0, - "y": 382, - "type": "TEXT", - "value": "379", - "last_modified": "2023-02-17T00:02:54.750Z" - }, - { - "x": 1, - "y": 382, - "type": "TEXT", - "value": "3Y3", - "last_modified": "2023-02-17T00:02:54.751Z" - }, - { - "x": 2, - "y": 382, - "type": "TEXT", - "value": "Winterset Madison County", - "last_modified": "2023-02-17T00:02:54.752Z" - }, - { - "x": 3, - "y": 382, - "type": "TEXT", - "value": "Winterset", - "last_modified": "2023-02-17T00:02:54.753Z" - }, - { - "x": 4, - "y": 382, - "type": "TEXT", - "value": "IA", - "last_modified": "2023-02-17T00:02:54.754Z" - }, - { - "x": 5, - "y": 382, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.755Z" - }, - { - "x": 6, - "y": 382, - "type": "TEXT", - "value": "41.36276778", - "last_modified": "2023-02-17T00:02:54.756Z" - }, - { - "x": 7, - "y": 382, - "type": "TEXT", - "value": "-94.02106194", - "last_modified": "2023-02-17T00:02:54.757Z" - }, - { - "x": 0, - "y": 383, - "type": "TEXT", - "value": "380", - "last_modified": "2023-02-17T00:02:54.759Z" - }, - { - "x": 1, - "y": 383, - "type": "TEXT", - "value": "3Z9", - "last_modified": "2023-02-17T00:02:54.760Z" - }, - { - "x": 2, - "y": 383, - "type": "TEXT", - "value": "Haines SPB", - "last_modified": "2023-02-17T00:02:54.761Z" - }, - { - "x": 3, - "y": 383, - "type": "TEXT", - "value": "Haines", - "last_modified": "2023-02-17T00:02:54.762Z" - }, - { - "x": 4, - "y": 383, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:54.763Z" - }, - { - "x": 5, - "y": 383, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.764Z" - }, - { - "x": 6, - "y": 383, - "type": "TEXT", - "value": "59.23495111", - "last_modified": "2023-02-17T00:02:54.765Z" - }, - { - "x": 7, - "y": 383, - "type": "TEXT", - "value": "-135.4407181", - "last_modified": "2023-02-17T00:02:54.766Z" - }, - { - "x": 0, - "y": 384, - "type": "TEXT", - "value": "381", - "last_modified": "2023-02-17T00:02:54.767Z" - }, - { - "x": 1, - "y": 384, - "type": "TEXT", - "value": "40J", - "last_modified": "2023-02-17T00:02:54.768Z" - }, - { - "x": 2, - "y": 384, - "type": "TEXT", - "value": "Perry-Foley", - "last_modified": "2023-02-17T00:02:54.769Z" - }, - { - "x": 3, - "y": 384, - "type": "TEXT", - "value": "Perry", - "last_modified": "2023-02-17T00:02:54.770Z" - }, - { - "x": 4, - "y": 384, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:54.771Z" - }, - { - "x": 5, - "y": 384, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.772Z" - }, - { - "x": 6, - "y": 384, - "type": "TEXT", - "value": "30.06927778", - "last_modified": "2023-02-17T00:02:54.773Z" - }, - { - "x": 7, - "y": 384, - "type": "TEXT", - "value": "-83.58058333", - "last_modified": "2023-02-17T00:02:54.774Z" - }, - { - "x": 0, - "y": 385, - "type": "TEXT", - "value": "382", - "last_modified": "2023-02-17T00:02:54.775Z" - }, - { - "x": 1, - "y": 385, - "type": "TEXT", - "value": "40N", - "last_modified": "2023-02-17T00:02:54.776Z" - }, - { - "x": 2, - "y": 385, - "type": "TEXT", - "value": "Chester Cty-G O Carlson", - "last_modified": "2023-02-17T00:02:54.777Z" - }, - { - "x": 3, - "y": 385, - "type": "TEXT", - "value": "Coatesville", - "last_modified": "2023-02-17T00:02:54.778Z" - }, - { - "x": 4, - "y": 385, - "type": "TEXT", - "value": "PA", - "last_modified": "2023-02-17T00:02:54.779Z" - }, - { - "x": 5, - "y": 385, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.780Z" - }, - { - "x": 6, - "y": 385, - "type": "TEXT", - "value": "39.97897222", - "last_modified": "2023-02-17T00:02:54.781Z" - }, - { - "x": 7, - "y": 385, - "type": "TEXT", - "value": "-75.86547222", - "last_modified": "2023-02-17T00:02:54.782Z" - }, - { - "x": 0, - "y": 386, - "type": "TEXT", - "value": "383", - "last_modified": "2023-02-17T00:02:54.783Z" - }, - { - "x": 1, - "y": 386, - "type": "TEXT", - "value": "40U", - "last_modified": "2023-02-17T00:02:54.784Z" - }, - { - "x": 2, - "y": 386, - "type": "TEXT", - "value": "Manila", - "last_modified": "2023-02-17T00:02:54.785Z" - }, - { - "x": 3, - "y": 386, - "type": "TEXT", - "value": "Manila", - "last_modified": "2023-02-17T00:02:54.786Z" - }, - { - "x": 4, - "y": 386, - "type": "TEXT", - "value": "UT", - "last_modified": "2023-02-17T00:02:54.787Z" - }, - { - "x": 5, - "y": 386, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.788Z" - }, - { - "x": 6, - "y": 386, - "type": "TEXT", - "value": "40.98607", - "last_modified": "2023-02-17T00:02:54.789Z" - }, - { - "x": 7, - "y": 386, - "type": "TEXT", - "value": "-109.6784811", - "last_modified": "2023-02-17T00:02:54.790Z" - }, - { - "x": 0, - "y": 387, - "type": "TEXT", - "value": "384", - "last_modified": "2023-02-17T00:02:54.791Z" - }, - { - "x": 1, - "y": 387, - "type": "TEXT", - "value": "41U", - "last_modified": "2023-02-17T00:02:54.792Z" - }, - { - "x": 2, - "y": 387, - "type": "TEXT", - "value": "Manti-Ephraim", - "last_modified": "2023-02-17T00:02:54.793Z" - }, - { - "x": 3, - "y": 387, - "type": "TEXT", - "value": "Manti", - "last_modified": "2023-02-17T00:02:54.794Z" - }, - { - "x": 4, - "y": 387, - "type": "TEXT", - "value": "UT", - "last_modified": "2023-02-17T00:02:54.795Z" - }, - { - "x": 5, - "y": 387, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.796Z" - }, - { - "x": 6, - "y": 387, - "type": "TEXT", - "value": "39.32912833", - "last_modified": "2023-02-17T00:02:54.797Z" - }, - { - "x": 7, - "y": 387, - "type": "TEXT", - "value": "-111.6146397", - "last_modified": "2023-02-17T00:02:54.798Z" - }, - { - "x": 0, - "y": 388, - "type": "TEXT", - "value": "385", - "last_modified": "2023-02-17T00:02:54.799Z" - }, - { - "x": 1, - "y": 388, - "type": "TEXT", - "value": "42A", - "last_modified": "2023-02-17T00:02:54.800Z" - }, - { - "x": 2, - "y": 388, - "type": "TEXT", - "value": "Melbourne Municipal", - "last_modified": "2023-02-17T00:02:54.801Z" - }, - { - "x": 3, - "y": 388, - "type": "TEXT", - "value": "Melbourne", - "last_modified": "2023-02-17T00:02:54.802Z" - }, - { - "x": 4, - "y": 388, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:54.803Z" - }, - { - "x": 5, - "y": 388, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.804Z" - }, - { - "x": 6, - "y": 388, - "type": "TEXT", - "value": "36.07079222", - "last_modified": "2023-02-17T00:02:54.805Z" - }, - { - "x": 7, - "y": 388, - "type": "TEXT", - "value": "-91.82914667", - "last_modified": "2023-02-17T00:02:54.806Z" - }, - { - "x": 0, - "y": 389, - "type": "TEXT", - "value": "386", - "last_modified": "2023-02-17T00:02:54.807Z" - }, - { - "x": 1, - "y": 389, - "type": "TEXT", - "value": "42C", - "last_modified": "2023-02-17T00:02:54.808Z" - }, - { - "x": 2, - "y": 389, - "type": "TEXT", - "value": "White Cloud", - "last_modified": "2023-02-17T00:02:54.808Z" - }, - { - "x": 3, - "y": 389, - "type": "TEXT", - "value": "White Cloud", - "last_modified": "2023-02-17T00:02:54.809Z" - }, - { - "x": 4, - "y": 389, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:54.810Z" - }, - { - "x": 5, - "y": 389, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.811Z" - }, - { - "x": 6, - "y": 389, - "type": "TEXT", - "value": "43.55974139", - "last_modified": "2023-02-17T00:02:54.812Z" - }, - { - "x": 7, - "y": 389, - "type": "TEXT", - "value": "-85.77421944", - "last_modified": "2023-02-17T00:02:54.813Z" - }, - { - "x": 0, - "y": 390, - "type": "TEXT", - "value": "387", - "last_modified": "2023-02-17T00:02:54.814Z" - }, - { - "x": 1, - "y": 390, - "type": "TEXT", - "value": "42J", - "last_modified": "2023-02-17T00:02:54.815Z" - }, - { - "x": 2, - "y": 390, - "type": "TEXT", - "value": "Keystone Airpark", - "last_modified": "2023-02-17T00:02:54.816Z" - }, - { - "x": 3, - "y": 390, - "type": "TEXT", - "value": "Keystone Heights", - "last_modified": "2023-02-17T00:02:54.817Z" - }, - { - "x": 4, - "y": 390, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:54.818Z" - }, - { - "x": 5, - "y": 390, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.819Z" - }, - { - "x": 6, - "y": 390, - "type": "TEXT", - "value": "29.84475", - "last_modified": "2023-02-17T00:02:54.820Z" - }, - { - "x": 7, - "y": 390, - "type": "TEXT", - "value": "-82.04752778", - "last_modified": "2023-02-17T00:02:54.821Z" - }, - { - "x": 0, - "y": 391, - "type": "TEXT", - "value": "388", - "last_modified": "2023-02-17T00:02:54.822Z" - }, - { - "x": 1, - "y": 391, - "type": "TEXT", - "value": "42S", - "last_modified": "2023-02-17T00:02:54.823Z" - }, - { - "x": 2, - "y": 391, - "type": "TEXT", - "value": "Poplar", - "last_modified": "2023-02-17T00:02:54.823Z" - }, - { - "x": 3, - "y": 391, - "type": "TEXT", - "value": "Poplar", - "last_modified": "2023-02-17T00:02:54.824Z" - }, - { - "x": 4, - "y": 391, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:54.825Z" - }, - { - "x": 5, - "y": 391, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.826Z" - }, - { - "x": 6, - "y": 391, - "type": "TEXT", - "value": "48.11595861", - "last_modified": "2023-02-17T00:02:54.827Z" - }, - { - "x": 7, - "y": 391, - "type": "TEXT", - "value": "-105.1821928", - "last_modified": "2023-02-17T00:02:54.828Z" - }, - { - "x": 0, - "y": 392, - "type": "TEXT", - "value": "389", - "last_modified": "2023-02-17T00:02:54.829Z" - }, - { - "x": 1, - "y": 392, - "type": "TEXT", - "value": "43A", - "last_modified": "2023-02-17T00:02:54.830Z" - }, - { - "x": 2, - "y": 392, - "type": "TEXT", - "value": "Montgomery County", - "last_modified": "2023-02-17T00:02:54.831Z" - }, - { - "x": 3, - "y": 392, - "type": "TEXT", - "value": "Star", - "last_modified": "2023-02-17T00:02:54.832Z" - }, - { - "x": 4, - "y": 392, - "type": "TEXT", - "value": "NC", - "last_modified": "2023-02-17T00:02:54.833Z" - }, - { - "x": 5, - "y": 392, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.834Z" - }, - { - "x": 6, - "y": 392, - "type": "TEXT", - "value": "35.38819528", - "last_modified": "2023-02-17T00:02:54.834Z" - }, - { - "x": 7, - "y": 392, - "type": "TEXT", - "value": "-79.79281667", - "last_modified": "2023-02-17T00:02:54.835Z" - }, - { - "x": 0, - "y": 393, - "type": "TEXT", - "value": "390", - "last_modified": "2023-02-17T00:02:54.836Z" - }, - { - "x": 1, - "y": 393, - "type": "TEXT", - "value": "44B", - "last_modified": "2023-02-17T00:02:54.837Z" - }, - { - "x": 2, - "y": 393, - "type": "TEXT", - "value": "Dover/Foxcroft", - "last_modified": "2023-02-17T00:02:54.838Z" - }, - { - "x": 3, - "y": 393, - "type": "TEXT", - "value": "Dover-Foxcroft", - "last_modified": "2023-02-17T00:02:54.839Z" - }, - { - "x": 4, - "y": 393, - "type": "TEXT", - "value": "ME", - "last_modified": "2023-02-17T00:02:54.840Z" - }, - { - "x": 5, - "y": 393, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.841Z" - }, - { - "x": 6, - "y": 393, - "type": "TEXT", - "value": "45.18338806", - "last_modified": "2023-02-17T00:02:54.842Z" - }, - { - "x": 7, - "y": 393, - "type": "TEXT", - "value": "-69.2328225", - "last_modified": "2023-02-17T00:02:54.843Z" - }, - { - "x": 0, - "y": 394, - "type": "TEXT", - "value": "391", - "last_modified": "2023-02-17T00:02:54.843Z" - }, - { - "x": 1, - "y": 394, - "type": "TEXT", - "value": "44N", - "last_modified": "2023-02-17T00:02:54.844Z" - }, - { - "x": 2, - "y": 394, - "type": "TEXT", - "value": "Sky Acres", - "last_modified": "2023-02-17T00:02:54.845Z" - }, - { - "x": 3, - "y": 394, - "type": "TEXT", - "value": "Millbrook", - "last_modified": "2023-02-17T00:02:54.846Z" - }, - { - "x": 4, - "y": 394, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:54.847Z" - }, - { - "x": 5, - "y": 394, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.848Z" - }, - { - "x": 6, - "y": 394, - "type": "TEXT", - "value": "41.70742861", - "last_modified": "2023-02-17T00:02:54.849Z" - }, - { - "x": 7, - "y": 394, - "type": "TEXT", - "value": "-73.73802889", - "last_modified": "2023-02-17T00:02:54.850Z" - }, - { - "x": 0, - "y": 395, - "type": "TEXT", - "value": "392", - "last_modified": "2023-02-17T00:02:54.850Z" - }, - { - "x": 1, - "y": 395, - "type": "TEXT", - "value": "45J", - "last_modified": "2023-02-17T00:02:54.851Z" - }, - { - "x": 2, - "y": 395, - "type": "TEXT", - "value": "Rockingham-Hamlet", - "last_modified": "2023-02-17T00:02:54.852Z" - }, - { - "x": 3, - "y": 395, - "type": "TEXT", - "value": "Rockingham", - "last_modified": "2023-02-17T00:02:54.853Z" - }, - { - "x": 4, - "y": 395, - "type": "TEXT", - "value": "NC", - "last_modified": "2023-02-17T00:02:54.854Z" - }, - { - "x": 5, - "y": 395, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.855Z" - }, - { - "x": 6, - "y": 395, - "type": "TEXT", - "value": "34.89107083", - "last_modified": "2023-02-17T00:02:54.856Z" - }, - { - "x": 7, - "y": 395, - "type": "TEXT", - "value": "-79.75905806", - "last_modified": "2023-02-17T00:02:54.856Z" - }, - { - "x": 0, - "y": 396, - "type": "TEXT", - "value": "393", - "last_modified": "2023-02-17T00:02:54.857Z" - }, - { - "x": 1, - "y": 396, - "type": "TEXT", - "value": "45OH", - "last_modified": "2023-02-17T00:02:54.858Z" - }, - { - "x": 2, - "y": 396, - "type": "TEXT", - "value": "North Bass Island", - "last_modified": "2023-02-17T00:02:54.859Z" - }, - { - "x": 3, - "y": 396, - "type": "TEXT", - "value": "North Bass Island", - "last_modified": "2023-02-17T00:02:54.860Z" - }, - { - "x": 4, - "y": 396, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:54.861Z" - }, - { - "x": 5, - "y": 396, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.862Z" - }, - { - "x": 6, - "y": 396, - "type": "TEXT", - "value": "41.71932528", - "last_modified": "2023-02-17T00:02:54.862Z" - }, - { - "x": 7, - "y": 396, - "type": "TEXT", - "value": "-82.82196917", - "last_modified": "2023-02-17T00:02:54.863Z" - }, - { - "x": 0, - "y": 397, - "type": "TEXT", - "value": "394", - "last_modified": "2023-02-17T00:02:54.864Z" - }, - { - "x": 1, - "y": 397, - "type": "TEXT", - "value": "45R", - "last_modified": "2023-02-17T00:02:54.865Z" - }, - { - "x": 2, - "y": 397, - "type": "TEXT", - "value": "Kountz - Hawthorne", - "last_modified": "2023-02-17T00:02:54.866Z" - }, - { - "x": 3, - "y": 397, - "type": "TEXT", - "value": "Kountze/Silsbee", - "last_modified": "2023-02-17T00:02:54.867Z" - }, - { - "x": 4, - "y": 397, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:54.868Z" - }, - { - "x": 5, - "y": 397, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.868Z" - }, - { - "x": 6, - "y": 397, - "type": "TEXT", - "value": "30.33633806", - "last_modified": "2023-02-17T00:02:54.869Z" - }, - { - "x": 7, - "y": 397, - "type": "TEXT", - "value": "-94.25754361", - "last_modified": "2023-02-17T00:02:54.870Z" - }, - { - "x": 0, - "y": 398, - "type": "TEXT", - "value": "395", - "last_modified": "2023-02-17T00:02:54.871Z" - }, - { - "x": 1, - "y": 398, - "type": "TEXT", - "value": "46A", - "last_modified": "2023-02-17T00:02:54.872Z" - }, - { - "x": 2, - "y": 398, - "type": "TEXT", - "value": "Blairsville", - "last_modified": "2023-02-17T00:02:54.873Z" - }, - { - "x": 3, - "y": 398, - "type": "TEXT", - "value": "Blairsville", - "last_modified": "2023-02-17T00:02:54.873Z" - }, - { - "x": 4, - "y": 398, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:54.874Z" - }, - { - "x": 5, - "y": 398, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.875Z" - }, - { - "x": 6, - "y": 398, - "type": "TEXT", - "value": "34.85508722", - "last_modified": "2023-02-17T00:02:54.876Z" - }, - { - "x": 7, - "y": 398, - "type": "TEXT", - "value": "-83.996855", - "last_modified": "2023-02-17T00:02:54.877Z" - }, - { - "x": 0, - "y": 399, - "type": "TEXT", - "value": "396", - "last_modified": "2023-02-17T00:02:54.877Z" - }, - { - "x": 1, - "y": 399, - "type": "TEXT", - "value": "46D", - "last_modified": "2023-02-17T00:02:54.878Z" - }, - { - "x": 2, - "y": 399, - "type": "TEXT", - "value": "Carrington Municipal", - "last_modified": "2023-02-17T00:02:54.879Z" - }, - { - "x": 3, - "y": 399, - "type": "TEXT", - "value": "Carrington", - "last_modified": "2023-02-17T00:02:54.880Z" - }, - { - "x": 4, - "y": 399, - "type": "TEXT", - "value": "ND", - "last_modified": "2023-02-17T00:02:54.881Z" - }, - { - "x": 5, - "y": 399, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.882Z" - }, - { - "x": 6, - "y": 399, - "type": "TEXT", - "value": "47.45111111", - "last_modified": "2023-02-17T00:02:54.882Z" - }, - { - "x": 7, - "y": 399, - "type": "TEXT", - "value": "-99.15111111", - "last_modified": "2023-02-17T00:02:54.883Z" - }, - { - "x": 0, - "y": 400, - "type": "TEXT", - "value": "397", - "last_modified": "2023-02-17T00:02:54.884Z" - }, - { - "x": 1, - "y": 400, - "type": "TEXT", - "value": "46N", - "last_modified": "2023-02-17T00:02:54.885Z" - }, - { - "x": 2, - "y": 400, - "type": "TEXT", - "value": "Sky Park", - "last_modified": "2023-02-17T00:02:54.886Z" - }, - { - "x": 3, - "y": 400, - "type": "TEXT", - "value": "Red Hook", - "last_modified": "2023-02-17T00:02:54.886Z" - }, - { - "x": 4, - "y": 400, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:54.887Z" - }, - { - "x": 5, - "y": 400, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.888Z" - }, - { - "x": 6, - "y": 400, - "type": "TEXT", - "value": "41.98458333", - "last_modified": "2023-02-17T00:02:54.889Z" - }, - { - "x": 7, - "y": 400, - "type": "TEXT", - "value": "-73.83596556", - "last_modified": "2023-02-17T00:02:54.890Z" - }, - { - "x": 0, - "y": 401, - "type": "TEXT", - "value": "398", - "last_modified": "2023-02-17T00:02:54.890Z" - }, - { - "x": 1, - "y": 401, - "type": "TEXT", - "value": "47A", - "last_modified": "2023-02-17T00:02:54.891Z" - }, - { - "x": 2, - "y": 401, - "type": "TEXT", - "value": "Cherokee County", - "last_modified": "2023-02-17T00:02:54.892Z" - }, - { - "x": 3, - "y": 401, - "type": "TEXT", - "value": "Canton", - "last_modified": "2023-02-17T00:02:54.893Z" - }, - { - "x": 4, - "y": 401, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:54.893Z" - }, - { - "x": 5, - "y": 401, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.894Z" - }, - { - "x": 6, - "y": 401, - "type": "TEXT", - "value": "34.31058333", - "last_modified": "2023-02-17T00:02:54.895Z" - }, - { - "x": 7, - "y": 401, - "type": "TEXT", - "value": "-84.42391667", - "last_modified": "2023-02-17T00:02:54.896Z" - }, - { - "x": 0, - "y": 402, - "type": "TEXT", - "value": "399", - "last_modified": "2023-02-17T00:02:54.897Z" - }, - { - "x": 1, - "y": 402, - "type": "TEXT", - "value": "47J", - "last_modified": "2023-02-17T00:02:54.897Z" - }, - { - "x": 2, - "y": 402, - "type": "TEXT", - "value": "Cheraw Municipal", - "last_modified": "2023-02-17T00:02:54.898Z" - }, - { - "x": 3, - "y": 402, - "type": "TEXT", - "value": "Cheraw", - "last_modified": "2023-02-17T00:02:54.899Z" - }, - { - "x": 4, - "y": 402, - "type": "TEXT", - "value": "SC", - "last_modified": "2023-02-17T00:02:54.900Z" - }, - { - "x": 5, - "y": 402, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.900Z" - }, - { - "x": 6, - "y": 402, - "type": "TEXT", - "value": "34.71258333", - "last_modified": "2023-02-17T00:02:54.901Z" - }, - { - "x": 7, - "y": 402, - "type": "TEXT", - "value": "-79.95794444", - "last_modified": "2023-02-17T00:02:54.902Z" - }, - { - "x": 0, - "y": 403, - "type": "TEXT", - "value": "400", - "last_modified": "2023-02-17T00:02:54.903Z" - }, - { - "x": 1, - "y": 403, - "type": "TEXT", - "value": "47N", - "last_modified": "2023-02-17T00:02:54.904Z" - }, - { - "x": 2, - "y": 403, - "type": "TEXT", - "value": "Central Jersey Regional", - "last_modified": "2023-02-17T00:02:54.904Z" - }, - { - "x": 3, - "y": 403, - "type": "TEXT", - "value": "Manville", - "last_modified": "2023-02-17T00:02:54.905Z" - }, - { - "x": 4, - "y": 403, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:54.906Z" - }, - { - "x": 5, - "y": 403, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.907Z" - }, - { - "x": 6, - "y": 403, - "type": "TEXT", - "value": "40.52438417", - "last_modified": "2023-02-17T00:02:54.907Z" - }, - { - "x": 7, - "y": 403, - "type": "TEXT", - "value": "-74.59839194", - "last_modified": "2023-02-17T00:02:54.908Z" - }, - { - "x": 0, - "y": 404, - "type": "TEXT", - "value": "401", - "last_modified": "2023-02-17T00:02:54.909Z" - }, - { - "x": 1, - "y": 404, - "type": "TEXT", - "value": "47V", - "last_modified": "2023-02-17T00:02:54.910Z" - }, - { - "x": 2, - "y": 404, - "type": "TEXT", - "value": "Curtis Municipal", - "last_modified": "2023-02-17T00:02:54.910Z" - }, - { - "x": 3, - "y": 404, - "type": "TEXT", - "value": "Curtis", - "last_modified": "2023-02-17T00:02:54.911Z" - }, - { - "x": 4, - "y": 404, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:54.912Z" - }, - { - "x": 5, - "y": 404, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.913Z" - }, - { - "x": 6, - "y": 404, - "type": "TEXT", - "value": "40.63750778", - "last_modified": "2023-02-17T00:02:54.914Z" - }, - { - "x": 7, - "y": 404, - "type": "TEXT", - "value": "-100.4712539", - "last_modified": "2023-02-17T00:02:54.914Z" - }, - { - "x": 0, - "y": 405, - "type": "TEXT", - "value": "402", - "last_modified": "2023-02-17T00:02:54.915Z" - }, - { - "x": 1, - "y": 405, - "type": "TEXT", - "value": "48A", - "last_modified": "2023-02-17T00:02:54.916Z" - }, - { - "x": 2, - "y": 405, - "type": "TEXT", - "value": "Cochran", - "last_modified": "2023-02-17T00:02:54.916Z" - }, - { - "x": 3, - "y": 405, - "type": "TEXT", - "value": "Cochran", - "last_modified": "2023-02-17T00:02:54.917Z" - }, - { - "x": 4, - "y": 405, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:54.918Z" - }, - { - "x": 5, - "y": 405, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.919Z" - }, - { - "x": 6, - "y": 405, - "type": "TEXT", - "value": "32.39936111", - "last_modified": "2023-02-17T00:02:54.919Z" - }, - { - "x": 7, - "y": 405, - "type": "TEXT", - "value": "-83.27591667", - "last_modified": "2023-02-17T00:02:54.920Z" - }, - { - "x": 0, - "y": 406, - "type": "TEXT", - "value": "403", - "last_modified": "2023-02-17T00:02:54.921Z" - }, - { - "x": 1, - "y": 406, - "type": "TEXT", - "value": "48D", - "last_modified": "2023-02-17T00:02:54.922Z" - }, - { - "x": 2, - "y": 406, - "type": "TEXT", - "value": "Clare Municipal", - "last_modified": "2023-02-17T00:02:54.922Z" - }, - { - "x": 3, - "y": 406, - "type": "TEXT", - "value": "Clare", - "last_modified": "2023-02-17T00:02:54.923Z" - }, - { - "x": 4, - "y": 406, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:54.924Z" - }, - { - "x": 5, - "y": 406, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.924Z" - }, - { - "x": 6, - "y": 406, - "type": "TEXT", - "value": "43.83111111", - "last_modified": "2023-02-17T00:02:54.925Z" - }, - { - "x": 7, - "y": 406, - "type": "TEXT", - "value": "-84.74133333", - "last_modified": "2023-02-17T00:02:54.926Z" - }, - { - "x": 0, - "y": 407, - "type": "TEXT", - "value": "404", - "last_modified": "2023-02-17T00:02:54.927Z" - }, - { - "x": 1, - "y": 407, - "type": "TEXT", - "value": "48I", - "last_modified": "2023-02-17T00:02:54.927Z" - }, - { - "x": 2, - "y": 407, - "type": "TEXT", - "value": "Braxton County", - "last_modified": "2023-02-17T00:02:54.928Z" - }, - { - "x": 3, - "y": 407, - "type": "TEXT", - "value": "Sutton", - "last_modified": "2023-02-17T00:02:54.929Z" - }, - { - "x": 4, - "y": 407, - "type": "TEXT", - "value": "WV", - "last_modified": "2023-02-17T00:02:54.929Z" - }, - { - "x": 5, - "y": 407, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.930Z" - }, - { - "x": 6, - "y": 407, - "type": "TEXT", - "value": "38.68704444", - "last_modified": "2023-02-17T00:02:54.931Z" - }, - { - "x": 7, - "y": 407, - "type": "TEXT", - "value": "-80.65176083", - "last_modified": "2023-02-17T00:02:54.932Z" - }, - { - "x": 0, - "y": 408, - "type": "TEXT", - "value": "405", - "last_modified": "2023-02-17T00:02:54.932Z" - }, - { - "x": 1, - "y": 408, - "type": "TEXT", - "value": "48K", - "last_modified": "2023-02-17T00:02:54.933Z" - }, - { - "x": 2, - "y": 408, - "type": "TEXT", - "value": "Ness City Municipal", - "last_modified": "2023-02-17T00:02:54.934Z" - }, - { - "x": 3, - "y": 408, - "type": "TEXT", - "value": "Ness City", - "last_modified": "2023-02-17T00:02:54.934Z" - }, - { - "x": 4, - "y": 408, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:54.935Z" - }, - { - "x": 5, - "y": 408, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.936Z" - }, - { - "x": 6, - "y": 408, - "type": "TEXT", - "value": "38.47110278", - "last_modified": "2023-02-17T00:02:54.937Z" - }, - { - "x": 7, - "y": 408, - "type": "TEXT", - "value": "-99.90806667", - "last_modified": "2023-02-17T00:02:54.937Z" - }, - { - "x": 0, - "y": 409, - "type": "TEXT", - "value": "406", - "last_modified": "2023-02-17T00:02:54.938Z" - }, - { - "x": 1, - "y": 409, - "type": "TEXT", - "value": "48S", - "last_modified": "2023-02-17T00:02:54.939Z" - }, - { - "x": 2, - "y": 409, - "type": "TEXT", - "value": "Harlem", - "last_modified": "2023-02-17T00:02:54.939Z" - }, - { - "x": 3, - "y": 409, - "type": "TEXT", - "value": "Harlem", - "last_modified": "2023-02-17T00:02:54.940Z" - }, - { - "x": 4, - "y": 409, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:54.941Z" - }, - { - "x": 5, - "y": 409, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.941Z" - }, - { - "x": 6, - "y": 409, - "type": "TEXT", - "value": "48.56666472", - "last_modified": "2023-02-17T00:02:54.942Z" - }, - { - "x": 7, - "y": 409, - "type": "TEXT", - "value": "-108.7729339", - "last_modified": "2023-02-17T00:02:54.943Z" - }, - { - "x": 0, - "y": 410, - "type": "TEXT", - "value": "407", - "last_modified": "2023-02-17T00:02:54.943Z" - }, - { - "x": 1, - "y": 410, - "type": "TEXT", - "value": "48V", - "last_modified": "2023-02-17T00:02:54.944Z" - }, - { - "x": 2, - "y": 410, - "type": "TEXT", - "value": "Tri-County", - "last_modified": "2023-02-17T00:02:54.945Z" - }, - { - "x": 3, - "y": 410, - "type": "TEXT", - "value": "Erie", - "last_modified": "2023-02-17T00:02:54.945Z" - }, - { - "x": 4, - "y": 410, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:54.946Z" - }, - { - "x": 5, - "y": 410, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.947Z" - }, - { - "x": 6, - "y": 410, - "type": "TEXT", - "value": "40.010225", - "last_modified": "2023-02-17T00:02:54.947Z" - }, - { - "x": 7, - "y": 410, - "type": "TEXT", - "value": "-105.047975", - "last_modified": "2023-02-17T00:02:54.948Z" - }, - { - "x": 0, - "y": 411, - "type": "TEXT", - "value": "408", - "last_modified": "2023-02-17T00:02:54.949Z" - }, - { - "x": 1, - "y": 411, - "type": "TEXT", - "value": "49A", - "last_modified": "2023-02-17T00:02:54.949Z" - }, - { - "x": 2, - "y": 411, - "type": "TEXT", - "value": "Gilmer County", - "last_modified": "2023-02-17T00:02:54.950Z" - }, - { - "x": 3, - "y": 411, - "type": "TEXT", - "value": "Ellijay", - "last_modified": "2023-02-17T00:02:54.951Z" - }, - { - "x": 4, - "y": 411, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:54.951Z" - }, - { - "x": 5, - "y": 411, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.952Z" - }, - { - "x": 6, - "y": 411, - "type": "TEXT", - "value": "34.62786417", - "last_modified": "2023-02-17T00:02:54.953Z" - }, - { - "x": 7, - "y": 411, - "type": "TEXT", - "value": "-84.52492889", - "last_modified": "2023-02-17T00:02:54.953Z" - }, - { - "x": 0, - "y": 412, - "type": "TEXT", - "value": "409", - "last_modified": "2023-02-17T00:02:54.954Z" - }, - { - "x": 1, - "y": 412, - "type": "TEXT", - "value": "49T", - "last_modified": "2023-02-17T00:02:54.955Z" - }, - { - "x": 2, - "y": 412, - "type": "TEXT", - "value": "Downtown Heliport", - "last_modified": "2023-02-17T00:02:54.955Z" - }, - { - "x": 3, - "y": 412, - "type": "TEXT", - "value": "Dallas", - "last_modified": "2023-02-17T00:02:54.956Z" - }, - { - "x": 4, - "y": 412, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:54.957Z" - }, - { - "x": 5, - "y": 412, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.957Z" - }, - { - "x": 6, - "y": 412, - "type": "TEXT", - "value": "32.77333333", - "last_modified": "2023-02-17T00:02:54.958Z" - }, - { - "x": 7, - "y": 412, - "type": "TEXT", - "value": "-96.80027778", - "last_modified": "2023-02-17T00:02:54.959Z" - }, - { - "x": 0, - "y": 413, - "type": "TEXT", - "value": "410", - "last_modified": "2023-02-17T00:02:54.959Z" - }, - { - "x": 1, - "y": 413, - "type": "TEXT", - "value": "49X", - "last_modified": "2023-02-17T00:02:54.960Z" - }, - { - "x": 2, - "y": 413, - "type": "TEXT", - "value": "Chemehuevi Valley", - "last_modified": "2023-02-17T00:02:54.961Z" - }, - { - "x": 3, - "y": 413, - "type": "TEXT", - "value": "Chemehuevi Valley", - "last_modified": "2023-02-17T00:02:54.961Z" - }, - { - "x": 4, - "y": 413, - "type": "TEXT", - "value": "CA", - "last_modified": "2023-02-17T00:02:54.962Z" - }, - { - "x": 5, - "y": 413, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.962Z" - }, - { - "x": 6, - "y": 413, - "type": "TEXT", - "value": "34.52751083", - "last_modified": "2023-02-17T00:02:54.963Z" - }, - { - "x": 7, - "y": 413, - "type": "TEXT", - "value": "-114.4310697", - "last_modified": "2023-02-17T00:02:54.964Z" - }, - { - "x": 0, - "y": 414, - "type": "TEXT", - "value": "411", - "last_modified": "2023-02-17T00:02:54.964Z" - }, - { - "x": 1, - "y": 414, - "type": "TEXT", - "value": "49Y", - "last_modified": "2023-02-17T00:02:54.965Z" - }, - { - "x": 2, - "y": 414, - "type": "TEXT", - "value": "Fillmore County", - "last_modified": "2023-02-17T00:02:54.966Z" - }, - { - "x": 3, - "y": 414, - "type": "TEXT", - "value": "Preston", - "last_modified": "2023-02-17T00:02:54.966Z" - }, - { - "x": 4, - "y": 414, - "type": "TEXT", - "value": "MN", - "last_modified": "2023-02-17T00:02:54.967Z" - }, - { - "x": 5, - "y": 414, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.967Z" - }, - { - "x": 6, - "y": 414, - "type": "TEXT", - "value": "43.67676", - "last_modified": "2023-02-17T00:02:54.968Z" - }, - { - "x": 7, - "y": 414, - "type": "TEXT", - "value": "-92.17973444", - "last_modified": "2023-02-17T00:02:54.969Z" - }, - { - "x": 0, - "y": 415, - "type": "TEXT", - "value": "412", - "last_modified": "2023-02-17T00:02:54.969Z" - }, - { - "x": 1, - "y": 415, - "type": "TEXT", - "value": "4A2", - "last_modified": "2023-02-17T00:02:54.970Z" - }, - { - "x": 2, - "y": 415, - "type": "TEXT", - "value": "Atmautluak", - "last_modified": "2023-02-17T00:02:54.971Z" - }, - { - "x": 3, - "y": 415, - "type": "TEXT", - "value": "Atmautluak", - "last_modified": "2023-02-17T00:02:54.971Z" - }, - { - "x": 4, - "y": 415, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:54.972Z" - }, - { - "x": 5, - "y": 415, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.972Z" - }, - { - "x": 6, - "y": 415, - "type": "TEXT", - "value": "60.86674556", - "last_modified": "2023-02-17T00:02:54.973Z" - }, - { - "x": 7, - "y": 415, - "type": "TEXT", - "value": "-162.2731389", - "last_modified": "2023-02-17T00:02:54.974Z" - }, - { - "x": 0, - "y": 416, - "type": "TEXT", - "value": "413", - "last_modified": "2023-02-17T00:02:54.974Z" - }, - { - "x": 1, - "y": 416, - "type": "TEXT", - "value": "4A4", - "last_modified": "2023-02-17T00:02:54.975Z" - }, - { - "x": 2, - "y": 416, - "type": "TEXT", - "value": "Cornelius-Moore", - "last_modified": "2023-02-17T00:02:54.975Z" - }, - { - "x": 3, - "y": 416, - "type": "TEXT", - "value": "Cedartown", - "last_modified": "2023-02-17T00:02:54.976Z" - }, - { - "x": 4, - "y": 416, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:54.977Z" - }, - { - "x": 5, - "y": 416, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.977Z" - }, - { - "x": 6, - "y": 416, - "type": "TEXT", - "value": "34.01869444", - "last_modified": "2023-02-17T00:02:54.978Z" - }, - { - "x": 7, - "y": 416, - "type": "TEXT", - "value": "-85.14647222", - "last_modified": "2023-02-17T00:02:54.979Z" - }, - { - "x": 0, - "y": 417, - "type": "TEXT", - "value": "414", - "last_modified": "2023-02-17T00:02:54.979Z" - }, - { - "x": 1, - "y": 417, - "type": "TEXT", - "value": "4A5", - "last_modified": "2023-02-17T00:02:54.980Z" - }, - { - "x": 2, - "y": 417, - "type": "TEXT", - "value": "Marshall-Searcy County", - "last_modified": "2023-02-17T00:02:54.980Z" - }, - { - "x": 3, - "y": 417, - "type": "TEXT", - "value": "Marshall", - "last_modified": "2023-02-17T00:02:54.981Z" - }, - { - "x": 4, - "y": 417, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:54.981Z" - }, - { - "x": 5, - "y": 417, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.982Z" - }, - { - "x": 6, - "y": 417, - "type": "TEXT", - "value": "35.89893667", - "last_modified": "2023-02-17T00:02:54.983Z" - }, - { - "x": 7, - "y": 417, - "type": "TEXT", - "value": "-92.65588611", - "last_modified": "2023-02-17T00:02:54.983Z" - }, - { - "x": 0, - "y": 418, - "type": "TEXT", - "value": "415", - "last_modified": "2023-02-17T00:02:54.984Z" - }, - { - "x": 1, - "y": 418, - "type": "TEXT", - "value": "4A6", - "last_modified": "2023-02-17T00:02:54.984Z" - }, - { - "x": 2, - "y": 418, - "type": "TEXT", - "value": "Scottsboro Municipal", - "last_modified": "2023-02-17T00:02:54.985Z" - }, - { - "x": 3, - "y": 418, - "type": "TEXT", - "value": "Scottsboro", - "last_modified": "2023-02-17T00:02:54.986Z" - }, - { - "x": 4, - "y": 418, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:54.986Z" - }, - { - "x": 5, - "y": 418, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.987Z" - }, - { - "x": 6, - "y": 418, - "type": "TEXT", - "value": "34.68897278", - "last_modified": "2023-02-17T00:02:54.987Z" - }, - { - "x": 7, - "y": 418, - "type": "TEXT", - "value": "-86.0058125", - "last_modified": "2023-02-17T00:02:54.988Z" - }, - { - "x": 0, - "y": 419, - "type": "TEXT", - "value": "416", - "last_modified": "2023-02-17T00:02:54.988Z" - }, - { - "x": 1, - "y": 419, - "type": "TEXT", - "value": "4A7", - "last_modified": "2023-02-17T00:02:54.989Z" - }, - { - "x": 2, - "y": 419, - "type": "TEXT", - "value": "Clayton County", - "last_modified": "2023-02-17T00:02:54.990Z" - }, - { - "x": 3, - "y": 419, - "type": "TEXT", - "value": "Hampton", - "last_modified": "2023-02-17T00:02:54.990Z" - }, - { - "x": 4, - "y": 419, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:54.991Z" - }, - { - "x": 5, - "y": 419, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.991Z" - }, - { - "x": 6, - "y": 419, - "type": "TEXT", - "value": "33.38911111", - "last_modified": "2023-02-17T00:02:54.992Z" - }, - { - "x": 7, - "y": 419, - "type": "TEXT", - "value": "-84.33236111", - "last_modified": "2023-02-17T00:02:54.992Z" - }, - { - "x": 0, - "y": 420, - "type": "TEXT", - "value": "417", - "last_modified": "2023-02-17T00:02:54.993Z" - }, - { - "x": 1, - "y": 420, - "type": "TEXT", - "value": "4A9", - "last_modified": "2023-02-17T00:02:54.994Z" - }, - { - "x": 2, - "y": 420, - "type": "TEXT", - "value": "Isbell", - "last_modified": "2023-02-17T00:02:54.994Z" - }, - { - "x": 3, - "y": 420, - "type": "TEXT", - "value": "Fort Payne", - "last_modified": "2023-02-17T00:02:54.995Z" - }, - { - "x": 4, - "y": 420, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:54.995Z" - }, - { - "x": 5, - "y": 420, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:54.996Z" - }, - { - "x": 6, - "y": 420, - "type": "TEXT", - "value": "34.4728925", - "last_modified": "2023-02-17T00:02:54.996Z" - }, - { - "x": 7, - "y": 420, - "type": "TEXT", - "value": "-85.72221722", - "last_modified": "2023-02-17T00:02:54.997Z" - }, - { - "x": 0, - "y": 421, - "type": "TEXT", - "value": "418", - "last_modified": "2023-02-17T00:02:54.998Z" - }, - { - "x": 1, - "y": 421, - "type": "TEXT", - "value": "4B0", - "last_modified": "2023-02-17T00:02:54.998Z" - }, - { - "x": 2, - "y": 421, - "type": "TEXT", - "value": "South Albany", - "last_modified": "2023-02-17T00:02:54.999Z" - }, - { - "x": 3, - "y": 421, - "type": "TEXT", - "value": "South Bethlehem", - "last_modified": "2023-02-17T00:02:54.999Z" - }, - { - "x": 4, - "y": 421, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:55.000Z" - }, - { - "x": 5, - "y": 421, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.000Z" - }, - { - "x": 6, - "y": 421, - "type": "TEXT", - "value": "42.56072611", - "last_modified": "2023-02-17T00:02:55.001Z" - }, - { - "x": 7, - "y": 421, - "type": "TEXT", - "value": "-73.83395639", - "last_modified": "2023-02-17T00:02:55.001Z" - }, - { - "x": 0, - "y": 422, - "type": "TEXT", - "value": "419", - "last_modified": "2023-02-17T00:02:55.002Z" - }, - { - "x": 1, - "y": 422, - "type": "TEXT", - "value": "4B1", - "last_modified": "2023-02-17T00:02:55.003Z" - }, - { - "x": 2, - "y": 422, - "type": "TEXT", - "value": "Duanesburg", - "last_modified": "2023-02-17T00:02:55.003Z" - }, - { - "x": 3, - "y": 422, - "type": "TEXT", - "value": "Duanesburg", - "last_modified": "2023-02-17T00:02:55.004Z" - }, - { - "x": 4, - "y": 422, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:55.004Z" - }, - { - "x": 5, - "y": 422, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.005Z" - }, - { - "x": 6, - "y": 422, - "type": "TEXT", - "value": "42.75840889", - "last_modified": "2023-02-17T00:02:55.005Z" - }, - { - "x": 7, - "y": 422, - "type": "TEXT", - "value": "-74.13290472", - "last_modified": "2023-02-17T00:02:55.006Z" - }, - { - "x": 0, - "y": 423, - "type": "TEXT", - "value": "420", - "last_modified": "2023-02-17T00:02:55.006Z" - }, - { - "x": 1, - "y": 423, - "type": "TEXT", - "value": "4B6", - "last_modified": "2023-02-17T00:02:55.007Z" - }, - { - "x": 2, - "y": 423, - "type": "TEXT", - "value": "Ticonderoga Muni", - "last_modified": "2023-02-17T00:02:55.007Z" - }, - { - "x": 3, - "y": 423, - "type": "TEXT", - "value": "Ticonderoga", - "last_modified": "2023-02-17T00:02:55.008Z" - }, - { - "x": 4, - "y": 423, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:55.008Z" - }, - { - "x": 5, - "y": 423, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.009Z" - }, - { - "x": 6, - "y": 423, - "type": "TEXT", - "value": "43.87700278", - "last_modified": "2023-02-17T00:02:55.009Z" - }, - { - "x": 7, - "y": 423, - "type": "TEXT", - "value": "-73.41317639", - "last_modified": "2023-02-17T00:02:55.010Z" - }, - { - "x": 0, - "y": 424, - "type": "TEXT", - "value": "421", - "last_modified": "2023-02-17T00:02:55.011Z" - }, - { - "x": 1, - "y": 424, - "type": "TEXT", - "value": "4B7", - "last_modified": "2023-02-17T00:02:55.011Z" - }, - { - "x": 2, - "y": 424, - "type": "TEXT", - "value": "Schroon Lake", - "last_modified": "2023-02-17T00:02:55.012Z" - }, - { - "x": 3, - "y": 424, - "type": "TEXT", - "value": "Schroon Lake", - "last_modified": "2023-02-17T00:02:55.012Z" - }, - { - "x": 4, - "y": 424, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:55.013Z" - }, - { - "x": 5, - "y": 424, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.013Z" - }, - { - "x": 6, - "y": 424, - "type": "TEXT", - "value": "43.86256083", - "last_modified": "2023-02-17T00:02:55.014Z" - }, - { - "x": 7, - "y": 424, - "type": "TEXT", - "value": "-73.74262972", - "last_modified": "2023-02-17T00:02:55.014Z" - }, - { - "x": 0, - "y": 425, - "type": "TEXT", - "value": "422", - "last_modified": "2023-02-17T00:02:55.015Z" - }, - { - "x": 1, - "y": 425, - "type": "TEXT", - "value": "4B8", - "last_modified": "2023-02-17T00:02:55.015Z" - }, - { - "x": 2, - "y": 425, - "type": "TEXT", - "value": "Robertson", - "last_modified": "2023-02-17T00:02:55.016Z" - }, - { - "x": 3, - "y": 425, - "type": "TEXT", - "value": "Plainville", - "last_modified": "2023-02-17T00:02:55.016Z" - }, - { - "x": 4, - "y": 425, - "type": "TEXT", - "value": "CT", - "last_modified": "2023-02-17T00:02:55.017Z" - }, - { - "x": 5, - "y": 425, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.017Z" - }, - { - "x": 6, - "y": 425, - "type": "TEXT", - "value": "41.69037667", - "last_modified": "2023-02-17T00:02:55.018Z" - }, - { - "x": 7, - "y": 425, - "type": "TEXT", - "value": "-72.8648225", - "last_modified": "2023-02-17T00:02:55.018Z" - }, - { - "x": 0, - "y": 426, - "type": "TEXT", - "value": "423", - "last_modified": "2023-02-17T00:02:55.019Z" - }, - { - "x": 1, - "y": 426, - "type": "TEXT", - "value": "4B9", - "last_modified": "2023-02-17T00:02:55.019Z" - }, - { - "x": 2, - "y": 426, - "type": "TEXT", - "value": "Simsbury Tri-Town", - "last_modified": "2023-02-17T00:02:55.020Z" - }, - { - "x": 3, - "y": 426, - "type": "TEXT", - "value": "Simsbury", - "last_modified": "2023-02-17T00:02:55.020Z" - }, - { - "x": 4, - "y": 426, - "type": "TEXT", - "value": "CT", - "last_modified": "2023-02-17T00:02:55.021Z" - }, - { - "x": 5, - "y": 426, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.021Z" - }, - { - "x": 6, - "y": 426, - "type": "TEXT", - "value": "41.91676389", - "last_modified": "2023-02-17T00:02:55.022Z" - }, - { - "x": 7, - "y": 426, - "type": "TEXT", - "value": "-72.77731778", - "last_modified": "2023-02-17T00:02:55.022Z" - }, - { - "x": 0, - "y": 427, - "type": "TEXT", - "value": "424", - "last_modified": "2023-02-17T00:02:55.023Z" - }, - { - "x": 1, - "y": 427, - "type": "TEXT", - "value": "4C8", - "last_modified": "2023-02-17T00:02:55.023Z" - }, - { - "x": 2, - "y": 427, - "type": "TEXT", - "value": "Albia Municipal", - "last_modified": "2023-02-17T00:02:55.024Z" - }, - { - "x": 3, - "y": 427, - "type": "TEXT", - "value": "Albia", - "last_modified": "2023-02-17T00:02:55.024Z" - }, - { - "x": 4, - "y": 427, - "type": "TEXT", - "value": "IA", - "last_modified": "2023-02-17T00:02:55.025Z" - }, - { - "x": 5, - "y": 427, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.025Z" - }, - { - "x": 6, - "y": 427, - "type": "TEXT", - "value": "40.99445361", - "last_modified": "2023-02-17T00:02:55.026Z" - }, - { - "x": 7, - "y": 427, - "type": "TEXT", - "value": "-92.76297194", - "last_modified": "2023-02-17T00:02:55.026Z" - }, - { - "x": 0, - "y": 428, - "type": "TEXT", - "value": "425", - "last_modified": "2023-02-17T00:02:55.027Z" - }, - { - "x": 1, - "y": 428, - "type": "TEXT", - "value": "4D0", - "last_modified": "2023-02-17T00:02:55.027Z" - }, - { - "x": 2, - "y": 428, - "type": "TEXT", - "value": "Abrams Municipal", - "last_modified": "2023-02-17T00:02:55.028Z" - }, - { - "x": 3, - "y": 428, - "type": "TEXT", - "value": "Grandledge", - "last_modified": "2023-02-17T00:02:55.028Z" - }, - { - "x": 4, - "y": 428, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:55.029Z" - }, - { - "x": 5, - "y": 428, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.029Z" - }, - { - "x": 6, - "y": 428, - "type": "TEXT", - "value": "42.77420167", - "last_modified": "2023-02-17T00:02:55.030Z" - }, - { - "x": 7, - "y": 428, - "type": "TEXT", - "value": "-84.73309806", - "last_modified": "2023-02-17T00:02:55.030Z" - }, - { - "x": 0, - "y": 429, - "type": "TEXT", - "value": "426", - "last_modified": "2023-02-17T00:02:55.030Z" - }, - { - "x": 1, - "y": 429, - "type": "TEXT", - "value": "4D9", - "last_modified": "2023-02-17T00:02:55.031Z" - }, - { - "x": 2, - "y": 429, - "type": "TEXT", - "value": "Alma Municipal", - "last_modified": "2023-02-17T00:02:55.031Z" - }, - { - "x": 3, - "y": 429, - "type": "TEXT", - "value": "Alma", - "last_modified": "2023-02-17T00:02:55.032Z" - }, - { - "x": 4, - "y": 429, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:55.032Z" - }, - { - "x": 5, - "y": 429, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.033Z" - }, - { - "x": 6, - "y": 429, - "type": "TEXT", - "value": "40.11389972", - "last_modified": "2023-02-17T00:02:55.034Z" - }, - { - "x": 7, - "y": 429, - "type": "TEXT", - "value": "-99.34565306", - "last_modified": "2023-02-17T00:02:55.034Z" - }, - { - "x": 0, - "y": 430, - "type": "TEXT", - "value": "427", - "last_modified": "2023-02-17T00:02:55.034Z" - }, - { - "x": 1, - "y": 430, - "type": "TEXT", - "value": "4F2", - "last_modified": "2023-02-17T00:02:55.035Z" - }, - { - "x": 2, - "y": 430, - "type": "TEXT", - "value": "Panola County-Sharpe", - "last_modified": "2023-02-17T00:02:55.035Z" - }, - { - "x": 3, - "y": 430, - "type": "TEXT", - "value": "Carthage", - "last_modified": "2023-02-17T00:02:55.036Z" - }, - { - "x": 4, - "y": 430, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:55.036Z" - }, - { - "x": 5, - "y": 430, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.037Z" - }, - { - "x": 6, - "y": 430, - "type": "TEXT", - "value": "32.17608333", - "last_modified": "2023-02-17T00:02:55.037Z" - }, - { - "x": 7, - "y": 430, - "type": "TEXT", - "value": "-94.29880556", - "last_modified": "2023-02-17T00:02:55.038Z" - }, - { - "x": 0, - "y": 431, - "type": "TEXT", - "value": "428", - "last_modified": "2023-02-17T00:02:55.038Z" - }, - { - "x": 1, - "y": 431, - "type": "TEXT", - "value": "4F4", - "last_modified": "2023-02-17T00:02:55.039Z" - }, - { - "x": 2, - "y": 431, - "type": "TEXT", - "value": "Gilmer-Upshur County", - "last_modified": "2023-02-17T00:02:55.039Z" - }, - { - "x": 3, - "y": 431, - "type": "TEXT", - "value": "Gilmer", - "last_modified": "2023-02-17T00:02:55.039Z" - }, - { - "x": 4, - "y": 431, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:55.040Z" - }, - { - "x": 5, - "y": 431, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.040Z" - }, - { - "x": 6, - "y": 431, - "type": "TEXT", - "value": "32.699", - "last_modified": "2023-02-17T00:02:55.041Z" - }, - { - "x": 7, - "y": 431, - "type": "TEXT", - "value": "-94.94886111", - "last_modified": "2023-02-17T00:02:55.041Z" - }, - { - "x": 0, - "y": 432, - "type": "TEXT", - "value": "429", - "last_modified": "2023-02-17T00:02:55.042Z" - }, - { - "x": 1, - "y": 432, - "type": "TEXT", - "value": "4G1", - "last_modified": "2023-02-17T00:02:55.042Z" - }, - { - "x": 2, - "y": 432, - "type": "TEXT", - "value": "Greenville Muni", - "last_modified": "2023-02-17T00:02:55.043Z" - }, - { - "x": 3, - "y": 432, - "type": "TEXT", - "value": "Greenville", - "last_modified": "2023-02-17T00:02:55.043Z" - }, - { - "x": 4, - "y": 432, - "type": "TEXT", - "value": "PA", - "last_modified": "2023-02-17T00:02:55.043Z" - }, - { - "x": 5, - "y": 432, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.044Z" - }, - { - "x": 6, - "y": 432, - "type": "TEXT", - "value": "41.44683167", - "last_modified": "2023-02-17T00:02:55.044Z" - }, - { - "x": 7, - "y": 432, - "type": "TEXT", - "value": "-80.39126167", - "last_modified": "2023-02-17T00:02:55.045Z" - }, - { - "x": 0, - "y": 433, - "type": "TEXT", - "value": "430", - "last_modified": "2023-02-17T00:02:55.045Z" - }, - { - "x": 1, - "y": 433, - "type": "TEXT", - "value": "4G2", - "last_modified": "2023-02-17T00:02:55.046Z" - }, - { - "x": 2, - "y": 433, - "type": "TEXT", - "value": "Hamburg Inc.", - "last_modified": "2023-02-17T00:02:55.046Z" - }, - { - "x": 3, - "y": 433, - "type": "TEXT", - "value": "Hamburg", - "last_modified": "2023-02-17T00:02:55.047Z" - }, - { - "x": 4, - "y": 433, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:55.047Z" - }, - { - "x": 5, - "y": 433, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.047Z" - }, - { - "x": 6, - "y": 433, - "type": "TEXT", - "value": "42.7008925", - "last_modified": "2023-02-17T00:02:55.048Z" - }, - { - "x": 7, - "y": 433, - "type": "TEXT", - "value": "-78.91475694", - "last_modified": "2023-02-17T00:02:55.048Z" - }, - { - "x": 0, - "y": 434, - "type": "TEXT", - "value": "431", - "last_modified": "2023-02-17T00:02:55.049Z" - }, - { - "x": 1, - "y": 434, - "type": "TEXT", - "value": "4G5", - "last_modified": "2023-02-17T00:02:55.049Z" - }, - { - "x": 2, - "y": 434, - "type": "TEXT", - "value": "Monroe County", - "last_modified": "2023-02-17T00:02:55.050Z" - }, - { - "x": 3, - "y": 434, - "type": "TEXT", - "value": "Woodsfield", - "last_modified": "2023-02-17T00:02:55.050Z" - }, - { - "x": 4, - "y": 434, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:55.050Z" - }, - { - "x": 5, - "y": 434, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.051Z" - }, - { - "x": 6, - "y": 434, - "type": "TEXT", - "value": "39.77904472", - "last_modified": "2023-02-17T00:02:55.051Z" - }, - { - "x": 7, - "y": 434, - "type": "TEXT", - "value": "-81.10277222", - "last_modified": "2023-02-17T00:02:55.052Z" - }, - { - "x": 0, - "y": 435, - "type": "TEXT", - "value": "432", - "last_modified": "2023-02-17T00:02:55.052Z" - }, - { - "x": 1, - "y": 435, - "type": "TEXT", - "value": "4G6", - "last_modified": "2023-02-17T00:02:55.053Z" - }, - { - "x": 2, - "y": 435, - "type": "TEXT", - "value": "Hornell Muni", - "last_modified": "2023-02-17T00:02:55.053Z" - }, - { - "x": 3, - "y": 435, - "type": "TEXT", - "value": "Hornell", - "last_modified": "2023-02-17T00:02:55.053Z" - }, - { - "x": 4, - "y": 435, - "type": "TEXT", - "value": "NY", - "last_modified": "2023-02-17T00:02:55.054Z" - }, - { - "x": 5, - "y": 435, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.054Z" - }, - { - "x": 6, - "y": 435, - "type": "TEXT", - "value": "42.38214444", - "last_modified": "2023-02-17T00:02:55.055Z" - }, - { - "x": 7, - "y": 435, - "type": "TEXT", - "value": "-77.6821125", - "last_modified": "2023-02-17T00:02:55.055Z" - }, - { - "x": 0, - "y": 436, - "type": "TEXT", - "value": "433", - "last_modified": "2023-02-17T00:02:55.055Z" - }, - { - "x": 1, - "y": 436, - "type": "TEXT", - "value": "4G7", - "last_modified": "2023-02-17T00:02:55.056Z" - }, - { - "x": 2, - "y": 436, - "type": "TEXT", - "value": "Fairmont Muni", - "last_modified": "2023-02-17T00:02:55.056Z" - }, - { - "x": 3, - "y": 436, - "type": "TEXT", - "value": "Fairmont", - "last_modified": "2023-02-17T00:02:55.057Z" - }, - { - "x": 4, - "y": 436, - "type": "TEXT", - "value": "WV", - "last_modified": "2023-02-17T00:02:55.057Z" - }, - { - "x": 5, - "y": 436, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.057Z" - }, - { - "x": 6, - "y": 436, - "type": "TEXT", - "value": "39.44816667", - "last_modified": "2023-02-17T00:02:55.058Z" - }, - { - "x": 7, - "y": 436, - "type": "TEXT", - "value": "-80.16702778", - "last_modified": "2023-02-17T00:02:55.058Z" - }, - { - "x": 0, - "y": 437, - "type": "TEXT", - "value": "434", - "last_modified": "2023-02-17T00:02:55.059Z" - }, - { - "x": 1, - "y": 437, - "type": "TEXT", - "value": "4I0", - "last_modified": "2023-02-17T00:02:55.059Z" - }, - { - "x": 2, - "y": 437, - "type": "TEXT", - "value": "Mingo County", - "last_modified": "2023-02-17T00:02:55.059Z" - }, - { - "x": 3, - "y": 437, - "type": "TEXT", - "value": "Williamson", - "last_modified": "2023-02-17T00:02:55.060Z" - }, - { - "x": 4, - "y": 437, - "type": "TEXT", - "value": "WV", - "last_modified": "2023-02-17T00:02:55.060Z" - }, - { - "x": 5, - "y": 437, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.061Z" - }, - { - "x": 6, - "y": 437, - "type": "TEXT", - "value": "37.68760139", - "last_modified": "2023-02-17T00:02:55.061Z" - }, - { - "x": 7, - "y": 437, - "type": "TEXT", - "value": "-82.26097306", - "last_modified": "2023-02-17T00:02:55.062Z" - }, - { - "x": 0, - "y": 438, - "type": "TEXT", - "value": "435", - "last_modified": "2023-02-17T00:02:55.062Z" - }, - { - "x": 1, - "y": 438, - "type": "TEXT", - "value": "4I3", - "last_modified": "2023-02-17T00:02:55.062Z" - }, - { - "x": 2, - "y": 438, - "type": "TEXT", - "value": "Knox County", - "last_modified": "2023-02-17T00:02:55.063Z" - }, - { - "x": 3, - "y": 438, - "type": "TEXT", - "value": "Mount Vernon", - "last_modified": "2023-02-17T00:02:55.063Z" - }, - { - "x": 4, - "y": 438, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:55.063Z" - }, - { - "x": 5, - "y": 438, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.064Z" - }, - { - "x": 6, - "y": 438, - "type": "TEXT", - "value": "40.32872222", - "last_modified": "2023-02-17T00:02:55.064Z" - }, - { - "x": 7, - "y": 438, - "type": "TEXT", - "value": "-82.52377778", - "last_modified": "2023-02-17T00:02:55.065Z" - }, - { - "x": 0, - "y": 439, - "type": "TEXT", - "value": "436", - "last_modified": "2023-02-17T00:02:55.065Z" - }, - { - "x": 1, - "y": 439, - "type": "TEXT", - "value": "4I7", - "last_modified": "2023-02-17T00:02:55.065Z" - }, - { - "x": 2, - "y": 439, - "type": "TEXT", - "value": "Putnam County", - "last_modified": "2023-02-17T00:02:55.066Z" - }, - { - "x": 3, - "y": 439, - "type": "TEXT", - "value": "Greencastle", - "last_modified": "2023-02-17T00:02:55.066Z" - }, - { - "x": 4, - "y": 439, - "type": "TEXT", - "value": "IN", - "last_modified": "2023-02-17T00:02:55.067Z" - }, - { - "x": 5, - "y": 439, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.067Z" - }, - { - "x": 6, - "y": 439, - "type": "TEXT", - "value": "39.63359556", - "last_modified": "2023-02-17T00:02:55.067Z" - }, - { - "x": 7, - "y": 439, - "type": "TEXT", - "value": "-86.8138325", - "last_modified": "2023-02-17T00:02:55.068Z" - }, - { - "x": 0, - "y": 440, - "type": "TEXT", - "value": "437", - "last_modified": "2023-02-17T00:02:55.068Z" - }, - { - "x": 1, - "y": 440, - "type": "TEXT", - "value": "4I9", - "last_modified": "2023-02-17T00:02:55.068Z" - }, - { - "x": 2, - "y": 440, - "type": "TEXT", - "value": "Morrow County", - "last_modified": "2023-02-17T00:02:55.069Z" - }, - { - "x": 3, - "y": 440, - "type": "TEXT", - "value": "Mt. Gilead", - "last_modified": "2023-02-17T00:02:55.069Z" - }, - { - "x": 4, - "y": 440, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:55.070Z" - }, - { - "x": 5, - "y": 440, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.070Z" - }, - { - "x": 6, - "y": 440, - "type": "TEXT", - "value": "40.52452778", - "last_modified": "2023-02-17T00:02:55.070Z" - }, - { - "x": 7, - "y": 440, - "type": "TEXT", - "value": "-82.85005556", - "last_modified": "2023-02-17T00:02:55.071Z" - }, - { - "x": 0, - "y": 441, - "type": "TEXT", - "value": "438", - "last_modified": "2023-02-17T00:02:55.071Z" - }, - { - "x": 1, - "y": 441, - "type": "TEXT", - "value": "4J1", - "last_modified": "2023-02-17T00:02:55.071Z" - }, - { - "x": 2, - "y": 441, - "type": "TEXT", - "value": "Brantley County", - "last_modified": "2023-02-17T00:02:55.072Z" - }, - { - "x": 3, - "y": 441, - "type": "TEXT", - "value": "Nahunta", - "last_modified": "2023-02-17T00:02:55.072Z" - }, - { - "x": 4, - "y": 441, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:55.072Z" - }, - { - "x": 5, - "y": 441, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.073Z" - }, - { - "x": 6, - "y": 441, - "type": "TEXT", - "value": "31.21272417", - "last_modified": "2023-02-17T00:02:55.073Z" - }, - { - "x": 7, - "y": 441, - "type": "TEXT", - "value": "-81.90539083", - "last_modified": "2023-02-17T00:02:55.074Z" - }, - { - "x": 0, - "y": 442, - "type": "TEXT", - "value": "439", - "last_modified": "2023-02-17T00:02:55.074Z" - }, - { - "x": 1, - "y": 442, - "type": "TEXT", - "value": "4J2", - "last_modified": "2023-02-17T00:02:55.074Z" - }, - { - "x": 2, - "y": 442, - "type": "TEXT", - "value": "Berrien County", - "last_modified": "2023-02-17T00:02:55.075Z" - }, - { - "x": 3, - "y": 442, - "type": "TEXT", - "value": "Nashville", - "last_modified": "2023-02-17T00:02:55.075Z" - }, - { - "x": 4, - "y": 442, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:55.075Z" - }, - { - "x": 5, - "y": 442, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.076Z" - }, - { - "x": 6, - "y": 442, - "type": "TEXT", - "value": "31.21255556", - "last_modified": "2023-02-17T00:02:55.076Z" - }, - { - "x": 7, - "y": 442, - "type": "TEXT", - "value": "-83.22627778", - "last_modified": "2023-02-17T00:02:55.076Z" - }, - { - "x": 0, - "y": 443, - "type": "TEXT", - "value": "440", - "last_modified": "2023-02-17T00:02:55.077Z" - }, - { - "x": 1, - "y": 443, - "type": "TEXT", - "value": "4J5", - "last_modified": "2023-02-17T00:02:55.077Z" - }, - { - "x": 2, - "y": 443, - "type": "TEXT", - "value": "Quitman-Brooks County", - "last_modified": "2023-02-17T00:02:55.077Z" - }, - { - "x": 3, - "y": 443, - "type": "TEXT", - "value": "Quitman", - "last_modified": "2023-02-17T00:02:55.078Z" - }, - { - "x": 4, - "y": 443, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:55.078Z" - }, - { - "x": 5, - "y": 443, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.079Z" - }, - { - "x": 6, - "y": 443, - "type": "TEXT", - "value": "30.80575139", - "last_modified": "2023-02-17T00:02:55.079Z" - }, - { - "x": 7, - "y": 443, - "type": "TEXT", - "value": "-83.58654889", - "last_modified": "2023-02-17T00:02:55.079Z" - }, - { - "x": 0, - "y": 444, - "type": "TEXT", - "value": "441", - "last_modified": "2023-02-17T00:02:55.080Z" - }, - { - "x": 1, - "y": 444, - "type": "TEXT", - "value": "4J6", - "last_modified": "2023-02-17T00:02:55.080Z" - }, - { - "x": 2, - "y": 444, - "type": "TEXT", - "value": "St Marys", - "last_modified": "2023-02-17T00:02:55.080Z" - }, - { - "x": 3, - "y": 444, - "type": "TEXT", - "value": "St Marys", - "last_modified": "2023-02-17T00:02:55.081Z" - }, - { - "x": 4, - "y": 444, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:55.081Z" - }, - { - "x": 5, - "y": 444, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.081Z" - }, - { - "x": 6, - "y": 444, - "type": "TEXT", - "value": "30.75468028", - "last_modified": "2023-02-17T00:02:55.082Z" - }, - { - "x": 7, - "y": 444, - "type": "TEXT", - "value": "-81.55731917", - "last_modified": "2023-02-17T00:02:55.082Z" - }, - { - "x": 0, - "y": 445, - "type": "TEXT", - "value": "442", - "last_modified": "2023-02-17T00:02:55.082Z" - }, - { - "x": 1, - "y": 445, - "type": "TEXT", - "value": "4K0", - "last_modified": "2023-02-17T00:02:55.083Z" - }, - { - "x": 2, - "y": 445, - "type": "TEXT", - "value": "Pedro Bay", - "last_modified": "2023-02-17T00:02:55.083Z" - }, - { - "x": 3, - "y": 445, - "type": "TEXT", - "value": "Pedro Bay", - "last_modified": "2023-02-17T00:02:55.083Z" - }, - { - "x": 4, - "y": 445, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:55.084Z" - }, - { - "x": 5, - "y": 445, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.084Z" - }, - { - "x": 6, - "y": 445, - "type": "TEXT", - "value": "59.78960972", - "last_modified": "2023-02-17T00:02:55.084Z" - }, - { - "x": 7, - "y": 445, - "type": "TEXT", - "value": "-154.1238331", - "last_modified": "2023-02-17T00:02:55.085Z" - }, - { - "x": 0, - "y": 446, - "type": "TEXT", - "value": "443", - "last_modified": "2023-02-17T00:02:55.085Z" - }, - { - "x": 1, - "y": 446, - "type": "TEXT", - "value": "4K5", - "last_modified": "2023-02-17T00:02:55.085Z" - }, - { - "x": 2, - "y": 446, - "type": "TEXT", - "value": "Ouzinkie", - "last_modified": "2023-02-17T00:02:55.086Z" - }, - { - "x": 3, - "y": 446, - "type": "TEXT", - "value": "Ouzinkie", - "last_modified": "2023-02-17T00:02:55.086Z" - }, - { - "x": 4, - "y": 446, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:55.086Z" - }, - { - "x": 5, - "y": 446, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.087Z" - }, - { - "x": 6, - "y": 446, - "type": "TEXT", - "value": "57.92287611", - "last_modified": "2023-02-17T00:02:55.087Z" - }, - { - "x": 7, - "y": 446, - "type": "TEXT", - "value": "-152.5005111", - "last_modified": "2023-02-17T00:02:55.087Z" - }, - { - "x": 0, - "y": 447, - "type": "TEXT", - "value": "444", - "last_modified": "2023-02-17T00:02:55.088Z" - }, - { - "x": 1, - "y": 447, - "type": "TEXT", - "value": "4K6", - "last_modified": "2023-02-17T00:02:55.088Z" - }, - { - "x": 2, - "y": 447, - "type": "TEXT", - "value": "Bloomfield Municipal", - "last_modified": "2023-02-17T00:02:55.088Z" - }, - { - "x": 3, - "y": 447, - "type": "TEXT", - "value": "Bloomfield", - "last_modified": "2023-02-17T00:02:55.089Z" - }, - { - "x": 4, - "y": 447, - "type": "TEXT", - "value": "IA", - "last_modified": "2023-02-17T00:02:55.089Z" - }, - { - "x": 5, - "y": 447, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.089Z" - }, - { - "x": 6, - "y": 447, - "type": "TEXT", - "value": "40.73210556", - "last_modified": "2023-02-17T00:02:55.089Z" - }, - { - "x": 7, - "y": 447, - "type": "TEXT", - "value": "-92.42826889", - "last_modified": "2023-02-17T00:02:55.090Z" - }, - { - "x": 0, - "y": 448, - "type": "TEXT", - "value": "445", - "last_modified": "2023-02-17T00:02:55.090Z" - }, - { - "x": 1, - "y": 448, - "type": "TEXT", - "value": "4KA", - "last_modified": "2023-02-17T00:02:55.090Z" - }, - { - "x": 2, - "y": 448, - "type": "TEXT", - "value": "Tununak", - "last_modified": "2023-02-17T00:02:55.091Z" - }, - { - "x": 3, - "y": 448, - "type": "TEXT", - "value": "Tununak", - "last_modified": "2023-02-17T00:02:55.091Z" - }, - { - "x": 4, - "y": 448, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:55.091Z" - }, - { - "x": 5, - "y": 448, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.092Z" - }, - { - "x": 6, - "y": 448, - "type": "TEXT", - "value": "60.57559667", - "last_modified": "2023-02-17T00:02:55.092Z" - }, - { - "x": 7, - "y": 448, - "type": "TEXT", - "value": "-165.2731272", - "last_modified": "2023-02-17T00:02:55.092Z" - }, - { - "x": 0, - "y": 449, - "type": "TEXT", - "value": "446", - "last_modified": "2023-02-17T00:02:55.093Z" - }, - { - "x": 1, - "y": 449, - "type": "TEXT", - "value": "4M1", - "last_modified": "2023-02-17T00:02:55.093Z" - }, - { - "x": 2, - "y": 449, - "type": "TEXT", - "value": "Carroll County", - "last_modified": "2023-02-17T00:02:55.093Z" - }, - { - "x": 3, - "y": 449, - "type": "TEXT", - "value": "Berryville", - "last_modified": "2023-02-17T00:02:55.094Z" - }, - { - "x": 4, - "y": 449, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:55.094Z" - }, - { - "x": 5, - "y": 449, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.094Z" - }, - { - "x": 6, - "y": 449, - "type": "TEXT", - "value": "36.38340333", - "last_modified": "2023-02-17T00:02:55.094Z" - }, - { - "x": 7, - "y": 449, - "type": "TEXT", - "value": "-93.61685667", - "last_modified": "2023-02-17T00:02:55.095Z" - }, - { - "x": 0, - "y": 450, - "type": "TEXT", - "value": "447", - "last_modified": "2023-02-17T00:02:55.095Z" - }, - { - "x": 1, - "y": 450, - "type": "TEXT", - "value": "4M3", - "last_modified": "2023-02-17T00:02:55.095Z" - }, - { - "x": 2, - "y": 450, - "type": "TEXT", - "value": "Carlisle Municipal", - "last_modified": "2023-02-17T00:02:55.096Z" - }, - { - "x": 3, - "y": 450, - "type": "TEXT", - "value": "Carlisle", - "last_modified": "2023-02-17T00:02:55.096Z" - }, - { - "x": 4, - "y": 450, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:55.096Z" - }, - { - "x": 5, - "y": 450, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.097Z" - }, - { - "x": 6, - "y": 450, - "type": "TEXT", - "value": "34.80823", - "last_modified": "2023-02-17T00:02:55.097Z" - }, - { - "x": 7, - "y": 450, - "type": "TEXT", - "value": "-91.71205083", - "last_modified": "2023-02-17T00:02:55.097Z" - }, - { - "x": 0, - "y": 451, - "type": "TEXT", - "value": "448", - "last_modified": "2023-02-17T00:02:55.097Z" - }, - { - "x": 1, - "y": 451, - "type": "TEXT", - "value": "4M4", - "last_modified": "2023-02-17T00:02:55.098Z" - }, - { - "x": 2, - "y": 451, - "type": "TEXT", - "value": "Clinton Municipal", - "last_modified": "2023-02-17T00:02:55.098Z" - }, - { - "x": 3, - "y": 451, - "type": "TEXT", - "value": "Clinton", - "last_modified": "2023-02-17T00:02:55.098Z" - }, - { - "x": 4, - "y": 451, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:55.099Z" - }, - { - "x": 5, - "y": 451, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.099Z" - }, - { - "x": 6, - "y": 451, - "type": "TEXT", - "value": "35.59785528", - "last_modified": "2023-02-17T00:02:55.099Z" - }, - { - "x": 7, - "y": 451, - "type": "TEXT", - "value": "-92.45182472", - "last_modified": "2023-02-17T00:02:55.099Z" - }, - { - "x": 0, - "y": 452, - "type": "TEXT", - "value": "449", - "last_modified": "2023-02-17T00:02:55.100Z" - }, - { - "x": 1, - "y": 452, - "type": "TEXT", - "value": "4M7", - "last_modified": "2023-02-17T00:02:55.100Z" - }, - { - "x": 2, - "y": 452, - "type": "TEXT", - "value": "Russellville-Logan County", - "last_modified": "2023-02-17T00:02:55.100Z" - }, - { - "x": 3, - "y": 452, - "type": "TEXT", - "value": "Russellville", - "last_modified": "2023-02-17T00:02:55.101Z" - }, - { - "x": 4, - "y": 452, - "type": "TEXT", - "value": "KY", - "last_modified": "2023-02-17T00:02:55.101Z" - }, - { - "x": 5, - "y": 452, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.101Z" - }, - { - "x": 6, - "y": 452, - "type": "TEXT", - "value": "36.79991667", - "last_modified": "2023-02-17T00:02:55.101Z" - }, - { - "x": 7, - "y": 452, - "type": "TEXT", - "value": "-86.81016667", - "last_modified": "2023-02-17T00:02:55.102Z" - }, - { - "x": 0, - "y": 453, - "type": "TEXT", - "value": "450", - "last_modified": "2023-02-17T00:02:55.102Z" - }, - { - "x": 1, - "y": 453, - "type": "TEXT", - "value": "4M8", - "last_modified": "2023-02-17T00:02:55.102Z" - }, - { - "x": 2, - "y": 453, - "type": "TEXT", - "value": "Clarendon Municipal", - "last_modified": "2023-02-17T00:02:55.103Z" - }, - { - "x": 3, - "y": 453, - "type": "TEXT", - "value": "Clarendon", - "last_modified": "2023-02-17T00:02:55.103Z" - }, - { - "x": 4, - "y": 453, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:55.103Z" - }, - { - "x": 5, - "y": 453, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.103Z" - }, - { - "x": 6, - "y": 453, - "type": "TEXT", - "value": "34.64870694", - "last_modified": "2023-02-17T00:02:55.104Z" - }, - { - "x": 7, - "y": 453, - "type": "TEXT", - "value": "-91.39457111", - "last_modified": "2023-02-17T00:02:55.104Z" - }, - { - "x": 0, - "y": 454, - "type": "TEXT", - "value": "451", - "last_modified": "2023-02-17T00:02:55.104Z" - }, - { - "x": 1, - "y": 454, - "type": "TEXT", - "value": "4M9", - "last_modified": "2023-02-17T00:02:55.105Z" - }, - { - "x": 2, - "y": 454, - "type": "TEXT", - "value": "Corning Municipal", - "last_modified": "2023-02-17T00:02:55.105Z" - }, - { - "x": 3, - "y": 454, - "type": "TEXT", - "value": "Corning", - "last_modified": "2023-02-17T00:02:55.105Z" - }, - { - "x": 4, - "y": 454, - "type": "TEXT", - "value": "AR", - "last_modified": "2023-02-17T00:02:55.105Z" - }, - { - "x": 5, - "y": 454, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.106Z" - }, - { - "x": 6, - "y": 454, - "type": "TEXT", - "value": "36.40423139", - "last_modified": "2023-02-17T00:02:55.106Z" - }, - { - "x": 7, - "y": 454, - "type": "TEXT", - "value": "-90.64792639", - "last_modified": "2023-02-17T00:02:55.106Z" - }, - { - "x": 0, - "y": 455, - "type": "TEXT", - "value": "452", - "last_modified": "2023-02-17T00:02:55.106Z" - }, - { - "x": 1, - "y": 455, - "type": "TEXT", - "value": "4N1", - "last_modified": "2023-02-17T00:02:55.107Z" - }, - { - "x": 2, - "y": 455, - "type": "TEXT", - "value": "Greenwood Lake", - "last_modified": "2023-02-17T00:02:55.107Z" - }, - { - "x": 3, - "y": 455, - "type": "TEXT", - "value": "West Milford", - "last_modified": "2023-02-17T00:02:55.107Z" - }, - { - "x": 4, - "y": 455, - "type": "TEXT", - "value": "NJ", - "last_modified": "2023-02-17T00:02:55.107Z" - }, - { - "x": 5, - "y": 455, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.108Z" - }, - { - "x": 6, - "y": 455, - "type": "TEXT", - "value": "41.12854806", - "last_modified": "2023-02-17T00:02:55.108Z" - }, - { - "x": 7, - "y": 455, - "type": "TEXT", - "value": "-74.34584611", - "last_modified": "2023-02-17T00:02:55.108Z" - }, - { - "x": 0, - "y": 456, - "type": "TEXT", - "value": "453", - "last_modified": "2023-02-17T00:02:55.109Z" - }, - { - "x": 1, - "y": 456, - "type": "TEXT", - "value": "4O3", - "last_modified": "2023-02-17T00:02:55.109Z" - }, - { - "x": 2, - "y": 456, - "type": "TEXT", - "value": "Blackwell-Tonkawa Municipal", - "last_modified": "2023-02-17T00:02:55.109Z" - }, - { - "x": 3, - "y": 456, - "type": "TEXT", - "value": "Blackwell-Tonkawa", - "last_modified": "2023-02-17T00:02:55.109Z" - }, - { - "x": 4, - "y": 456, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:55.110Z" - }, - { - "x": 5, - "y": 456, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.110Z" - }, - { - "x": 6, - "y": 456, - "type": "TEXT", - "value": "36.74511583", - "last_modified": "2023-02-17T00:02:55.110Z" - }, - { - "x": 7, - "y": 456, - "type": "TEXT", - "value": "-97.34959972", - "last_modified": "2023-02-17T00:02:55.110Z" - }, - { - "x": 0, - "y": 457, - "type": "TEXT", - "value": "454", - "last_modified": "2023-02-17T00:02:55.111Z" - }, - { - "x": 1, - "y": 457, - "type": "TEXT", - "value": "4O4", - "last_modified": "2023-02-17T00:02:55.111Z" - }, - { - "x": 2, - "y": 457, - "type": "TEXT", - "value": "McCurtain County Regional", - "last_modified": "2023-02-17T00:02:55.111Z" - }, - { - "x": 3, - "y": 457, - "type": "TEXT", - "value": "Idabel", - "last_modified": "2023-02-17T00:02:55.111Z" - }, - { - "x": 4, - "y": 457, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:55.112Z" - }, - { - "x": 5, - "y": 457, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.112Z" - }, - { - "x": 6, - "y": 457, - "type": "TEXT", - "value": "33.909325", - "last_modified": "2023-02-17T00:02:55.112Z" - }, - { - "x": 7, - "y": 457, - "type": "TEXT", - "value": "-94.85835278", - "last_modified": "2023-02-17T00:02:55.113Z" - }, - { - "x": 0, - "y": 458, - "type": "TEXT", - "value": "455", - "last_modified": "2023-02-17T00:02:55.113Z" - }, - { - "x": 1, - "y": 458, - "type": "TEXT", - "value": "4O5", - "last_modified": "2023-02-17T00:02:55.113Z" - }, - { - "x": 2, - "y": 458, - "type": "TEXT", - "value": "Cherokee Municipal", - "last_modified": "2023-02-17T00:02:55.113Z" - }, - { - "x": 3, - "y": 458, - "type": "TEXT", - "value": "Cherokee", - "last_modified": "2023-02-17T00:02:55.114Z" - }, - { - "x": 4, - "y": 458, - "type": "TEXT", - "value": "OK", - "last_modified": "2023-02-17T00:02:55.114Z" - }, - { - "x": 5, - "y": 458, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.114Z" - }, - { - "x": 6, - "y": 458, - "type": "TEXT", - "value": "36.78336306", - "last_modified": "2023-02-17T00:02:55.114Z" - }, - { - "x": 7, - "y": 458, - "type": "TEXT", - "value": "-98.35035083", - "last_modified": "2023-02-17T00:02:55.115Z" - }, - { - "x": 0, - "y": 459, - "type": "TEXT", - "value": "456", - "last_modified": "2023-02-17T00:02:55.115Z" - }, - { - "x": 1, - "y": 459, - "type": "TEXT", - "value": "4PH", - "last_modified": "2023-02-17T00:02:55.115Z" - }, - { - "x": 2, - "y": 459, - "type": "TEXT", - "value": "Polacca", - "last_modified": "2023-02-17T00:02:55.115Z" - }, - { - "x": 3, - "y": 459, - "type": "TEXT", - "value": "Polacca", - "last_modified": "2023-02-17T00:02:55.116Z" - }, - { - "x": 4, - "y": 459, - "type": "TEXT", - "value": "AZ", - "last_modified": "2023-02-17T00:02:55.116Z" - }, - { - "x": 5, - "y": 459, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.116Z" - }, - { - "x": 6, - "y": 459, - "type": "TEXT", - "value": "35.79167222", - "last_modified": "2023-02-17T00:02:55.116Z" - }, - { - "x": 7, - "y": 459, - "type": "TEXT", - "value": "-110.4234653", - "last_modified": "2023-02-17T00:02:55.117Z" - }, - { - "x": 0, - "y": 460, - "type": "TEXT", - "value": "457", - "last_modified": "2023-02-17T00:02:55.117Z" - }, - { - "x": 1, - "y": 460, - "type": "TEXT", - "value": "4R1", - "last_modified": "2023-02-17T00:02:55.117Z" - }, - { - "x": 2, - "y": 460, - "type": "TEXT", - "value": "I H Bass Jr Memorial", - "last_modified": "2023-02-17T00:02:55.117Z" - }, - { - "x": 3, - "y": 460, - "type": "TEXT", - "value": "Lumberton", - "last_modified": "2023-02-17T00:02:55.117Z" - }, - { - "x": 4, - "y": 460, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:55.118Z" - }, - { - "x": 5, - "y": 460, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.118Z" - }, - { - "x": 6, - "y": 460, - "type": "TEXT", - "value": "31.01546028", - "last_modified": "2023-02-17T00:02:55.118Z" - }, - { - "x": 7, - "y": 460, - "type": "TEXT", - "value": "-89.48256556", - "last_modified": "2023-02-17T00:02:55.118Z" - }, - { - "x": 0, - "y": 461, - "type": "TEXT", - "value": "458", - "last_modified": "2023-02-17T00:02:55.119Z" - }, - { - "x": 1, - "y": 461, - "type": "TEXT", - "value": "4R3", - "last_modified": "2023-02-17T00:02:55.119Z" - }, - { - "x": 2, - "y": 461, - "type": "TEXT", - "value": "Jackson Municipal", - "last_modified": "2023-02-17T00:02:55.119Z" - }, - { - "x": 3, - "y": 461, - "type": "TEXT", - "value": "Jackson", - "last_modified": "2023-02-17T00:02:55.119Z" - }, - { - "x": 4, - "y": 461, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:55.120Z" - }, - { - "x": 5, - "y": 461, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.120Z" - }, - { - "x": 6, - "y": 461, - "type": "TEXT", - "value": "31.47210861", - "last_modified": "2023-02-17T00:02:55.120Z" - }, - { - "x": 7, - "y": 461, - "type": "TEXT", - "value": "-87.89472083", - "last_modified": "2023-02-17T00:02:55.120Z" - }, - { - "x": 0, - "y": 462, - "type": "TEXT", - "value": "459", - "last_modified": "2023-02-17T00:02:55.121Z" - }, - { - "x": 1, - "y": 462, - "type": "TEXT", - "value": "4R4", - "last_modified": "2023-02-17T00:02:55.121Z" - }, - { - "x": 2, - "y": 462, - "type": "TEXT", - "value": "Fairhope Municipal", - "last_modified": "2023-02-17T00:02:55.121Z" - }, - { - "x": 3, - "y": 462, - "type": "TEXT", - "value": "Fairhope", - "last_modified": "2023-02-17T00:02:55.121Z" - }, - { - "x": 4, - "y": 462, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:55.121Z" - }, - { - "x": 5, - "y": 462, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.122Z" - }, - { - "x": 6, - "y": 462, - "type": "TEXT", - "value": "30.4621125", - "last_modified": "2023-02-17T00:02:55.122Z" - }, - { - "x": 7, - "y": 462, - "type": "TEXT", - "value": "-87.87801972", - "last_modified": "2023-02-17T00:02:55.122Z" - }, - { - "x": 0, - "y": 463, - "type": "TEXT", - "value": "460", - "last_modified": "2023-02-17T00:02:55.122Z" - }, - { - "x": 1, - "y": 463, - "type": "TEXT", - "value": "4R5", - "last_modified": "2023-02-17T00:02:55.123Z" - }, - { - "x": 2, - "y": 463, - "type": "TEXT", - "value": "Madeline Island", - "last_modified": "2023-02-17T00:02:55.123Z" - }, - { - "x": 3, - "y": 463, - "type": "TEXT", - "value": "La Pointe", - "last_modified": "2023-02-17T00:02:55.123Z" - }, - { - "x": 4, - "y": 463, - "type": "TEXT", - "value": "WI", - "last_modified": "2023-02-17T00:02:55.123Z" - }, - { - "x": 5, - "y": 463, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.123Z" - }, - { - "x": 6, - "y": 463, - "type": "TEXT", - "value": "46.78865556", - "last_modified": "2023-02-17T00:02:55.124Z" - }, - { - "x": 7, - "y": 463, - "type": "TEXT", - "value": "-90.75866944", - "last_modified": "2023-02-17T00:02:55.124Z" - }, - { - "x": 0, - "y": 464, - "type": "TEXT", - "value": "461", - "last_modified": "2023-02-17T00:02:55.124Z" - }, - { - "x": 1, - "y": 464, - "type": "TEXT", - "value": "4R7", - "last_modified": "2023-02-17T00:02:55.124Z" - }, - { - "x": 2, - "y": 464, - "type": "TEXT", - "value": "Eunice", - "last_modified": "2023-02-17T00:02:55.124Z" - }, - { - "x": 3, - "y": 464, - "type": "TEXT", - "value": "Eunice", - "last_modified": "2023-02-17T00:02:55.125Z" - }, - { - "x": 4, - "y": 464, - "type": "TEXT", - "value": "LA", - "last_modified": "2023-02-17T00:02:55.125Z" - }, - { - "x": 5, - "y": 464, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.125Z" - }, - { - "x": 6, - "y": 464, - "type": "TEXT", - "value": "30.46628389", - "last_modified": "2023-02-17T00:02:55.125Z" - }, - { - "x": 7, - "y": 464, - "type": "TEXT", - "value": "-92.42379917", - "last_modified": "2023-02-17T00:02:55.126Z" - }, - { - "x": 0, - "y": 465, - "type": "TEXT", - "value": "462", - "last_modified": "2023-02-17T00:02:55.126Z" - }, - { - "x": 1, - "y": 465, - "type": "TEXT", - "value": "4R9", - "last_modified": "2023-02-17T00:02:55.126Z" - }, - { - "x": 2, - "y": 465, - "type": "TEXT", - "value": "Dauphin Island", - "last_modified": "2023-02-17T00:02:55.126Z" - }, - { - "x": 3, - "y": 465, - "type": "TEXT", - "value": "Dauphin Island", - "last_modified": "2023-02-17T00:02:55.126Z" - }, - { - "x": 4, - "y": 465, - "type": "TEXT", - "value": "AL", - "last_modified": "2023-02-17T00:02:55.127Z" - }, - { - "x": 5, - "y": 465, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.127Z" - }, - { - "x": 6, - "y": 465, - "type": "TEXT", - "value": "30.26048083", - "last_modified": "2023-02-17T00:02:55.127Z" - }, - { - "x": 7, - "y": 465, - "type": "TEXT", - "value": "-88.12749972", - "last_modified": "2023-02-17T00:02:55.127Z" - }, - { - "x": 0, - "y": 466, - "type": "TEXT", - "value": "463", - "last_modified": "2023-02-17T00:02:55.128Z" - }, - { - "x": 1, - "y": 466, - "type": "TEXT", - "value": "4S1", - "last_modified": "2023-02-17T00:02:55.128Z" - }, - { - "x": 2, - "y": 466, - "type": "TEXT", - "value": "Gold Beach Muni", - "last_modified": "2023-02-17T00:02:55.128Z" - }, - { - "x": 3, - "y": 466, - "type": "TEXT", - "value": "Gold Beach", - "last_modified": "2023-02-17T00:02:55.128Z" - }, - { - "x": 4, - "y": 466, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:55.128Z" - }, - { - "x": 5, - "y": 466, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.129Z" - }, - { - "x": 6, - "y": 466, - "type": "TEXT", - "value": "42.41344444", - "last_modified": "2023-02-17T00:02:55.129Z" - }, - { - "x": 7, - "y": 466, - "type": "TEXT", - "value": "-124.4242742", - "last_modified": "2023-02-17T00:02:55.129Z" - }, - { - "x": 0, - "y": 467, - "type": "TEXT", - "value": "464", - "last_modified": "2023-02-17T00:02:55.129Z" - }, - { - "x": 1, - "y": 467, - "type": "TEXT", - "value": "4S2", - "last_modified": "2023-02-17T00:02:55.129Z" - }, - { - "x": 2, - "y": 467, - "type": "TEXT", - "value": "Hood River", - "last_modified": "2023-02-17T00:02:55.130Z" - }, - { - "x": 3, - "y": 467, - "type": "TEXT", - "value": "Hood River", - "last_modified": "2023-02-17T00:02:55.130Z" - }, - { - "x": 4, - "y": 467, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:55.130Z" - }, - { - "x": 5, - "y": 467, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.130Z" - }, - { - "x": 6, - "y": 467, - "type": "TEXT", - "value": "45.67261833", - "last_modified": "2023-02-17T00:02:55.130Z" - }, - { - "x": 7, - "y": 467, - "type": "TEXT", - "value": "-121.5364625", - "last_modified": "2023-02-17T00:02:55.131Z" - }, - { - "x": 0, - "y": 468, - "type": "TEXT", - "value": "465", - "last_modified": "2023-02-17T00:02:55.131Z" - }, - { - "x": 1, - "y": 468, - "type": "TEXT", - "value": "4S3", - "last_modified": "2023-02-17T00:02:55.131Z" - }, - { - "x": 2, - "y": 468, - "type": "TEXT", - "value": "Joseph State", - "last_modified": "2023-02-17T00:02:55.131Z" - }, - { - "x": 3, - "y": 468, - "type": "TEXT", - "value": "Joseph", - "last_modified": "2023-02-17T00:02:55.131Z" - }, - { - "x": 4, - "y": 468, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:55.132Z" - }, - { - "x": 5, - "y": 468, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.132Z" - }, - { - "x": 6, - "y": 468, - "type": "TEXT", - "value": "45.35709583", - "last_modified": "2023-02-17T00:02:55.132Z" - }, - { - "x": 7, - "y": 468, - "type": "TEXT", - "value": "-117.2532244", - "last_modified": "2023-02-17T00:02:55.132Z" - }, - { - "x": 0, - "y": 469, - "type": "TEXT", - "value": "466", - "last_modified": "2023-02-17T00:02:55.132Z" - }, - { - "x": 1, - "y": 469, - "type": "TEXT", - "value": "4S9", - "last_modified": "2023-02-17T00:02:55.132Z" - }, - { - "x": 2, - "y": 469, - "type": "TEXT", - "value": "Portland-Mulino", - "last_modified": "2023-02-17T00:02:55.133Z" - }, - { - "x": 3, - "y": 469, - "type": "TEXT", - "value": "Mulino (Portland)", - "last_modified": "2023-02-17T00:02:55.133Z" - }, - { - "x": 4, - "y": 469, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:55.133Z" - }, - { - "x": 5, - "y": 469, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.133Z" - }, - { - "x": 6, - "y": 469, - "type": "TEXT", - "value": "45.21632417", - "last_modified": "2023-02-17T00:02:55.133Z" - }, - { - "x": 7, - "y": 469, - "type": "TEXT", - "value": "-122.5900839", - "last_modified": "2023-02-17T00:02:55.134Z" - }, - { - "x": 0, - "y": 470, - "type": "TEXT", - "value": "467", - "last_modified": "2023-02-17T00:02:55.134Z" - }, - { - "x": 1, - "y": 470, - "type": "TEXT", - "value": "4SD", - "last_modified": "2023-02-17T00:02:55.134Z" - }, - { - "x": 2, - "y": 470, - "type": "TEXT", - "value": "Reno/Stead", - "last_modified": "2023-02-17T00:02:55.134Z" - }, - { - "x": 3, - "y": 470, - "type": "TEXT", - "value": "Reno", - "last_modified": "2023-02-17T00:02:55.135Z" - }, - { - "x": 4, - "y": 470, - "type": "TEXT", - "value": "NV", - "last_modified": "2023-02-17T00:02:55.135Z" - }, - { - "x": 5, - "y": 470, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.135Z" - }, - { - "x": 6, - "y": 470, - "type": "TEXT", - "value": "39.66738111", - "last_modified": "2023-02-17T00:02:55.135Z" - }, - { - "x": 7, - "y": 470, - "type": "TEXT", - "value": "-119.8754169", - "last_modified": "2023-02-17T00:02:55.135Z" - }, - { - "x": 0, - "y": 471, - "type": "TEXT", - "value": "468", - "last_modified": "2023-02-17T00:02:55.136Z" - }, - { - "x": 1, - "y": 471, - "type": "TEXT", - "value": "4T6", - "last_modified": "2023-02-17T00:02:55.136Z" - }, - { - "x": 2, - "y": 471, - "type": "TEXT", - "value": "Mid-Way", - "last_modified": "2023-02-17T00:02:55.136Z" - }, - { - "x": 3, - "y": 471, - "type": "TEXT", - "value": "Midlothian-Waxahachie", - "last_modified": "2023-02-17T00:02:55.136Z" - }, - { - "x": 4, - "y": 471, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:55.136Z" - }, - { - "x": 5, - "y": 471, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.136Z" - }, - { - "x": 6, - "y": 471, - "type": "TEXT", - "value": "32.45609722", - "last_modified": "2023-02-17T00:02:55.137Z" - }, - { - "x": 7, - "y": 471, - "type": "TEXT", - "value": "-96.91240972", - "last_modified": "2023-02-17T00:02:55.137Z" - }, - { - "x": 0, - "y": 472, - "type": "TEXT", - "value": "469", - "last_modified": "2023-02-17T00:02:55.137Z" - }, - { - "x": 1, - "y": 472, - "type": "TEXT", - "value": "4U3", - "last_modified": "2023-02-17T00:02:55.137Z" - }, - { - "x": 2, - "y": 472, - "type": "TEXT", - "value": "Liberty County", - "last_modified": "2023-02-17T00:02:55.137Z" - }, - { - "x": 3, - "y": 472, - "type": "TEXT", - "value": "Chester", - "last_modified": "2023-02-17T00:02:55.138Z" - }, - { - "x": 4, - "y": 472, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:55.138Z" - }, - { - "x": 5, - "y": 472, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.138Z" - }, - { - "x": 6, - "y": 472, - "type": "TEXT", - "value": "48.51072222", - "last_modified": "2023-02-17T00:02:55.138Z" - }, - { - "x": 7, - "y": 472, - "type": "TEXT", - "value": "-110.9908639", - "last_modified": "2023-02-17T00:02:55.138Z" - }, - { - "x": 0, - "y": 473, - "type": "TEXT", - "value": "470", - "last_modified": "2023-02-17T00:02:55.138Z" - }, - { - "x": 1, - "y": 473, - "type": "TEXT", - "value": "4U6", - "last_modified": "2023-02-17T00:02:55.139Z" - }, - { - "x": 2, - "y": 473, - "type": "TEXT", - "value": "Circle Town County", - "last_modified": "2023-02-17T00:02:55.139Z" - }, - { - "x": 3, - "y": 473, - "type": "TEXT", - "value": "Circle", - "last_modified": "2023-02-17T00:02:55.139Z" - }, - { - "x": 4, - "y": 473, - "type": "TEXT", - "value": "MT", - "last_modified": "2023-02-17T00:02:55.139Z" - }, - { - "x": 5, - "y": 473, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.139Z" - }, - { - "x": 6, - "y": 473, - "type": "TEXT", - "value": "47.41861972", - "last_modified": "2023-02-17T00:02:55.139Z" - }, - { - "x": 7, - "y": 473, - "type": "TEXT", - "value": "-105.5619431", - "last_modified": "2023-02-17T00:02:55.140Z" - }, - { - "x": 0, - "y": 474, - "type": "TEXT", - "value": "471", - "last_modified": "2023-02-17T00:02:55.140Z" - }, - { - "x": 1, - "y": 474, - "type": "TEXT", - "value": "4V0", - "last_modified": "2023-02-17T00:02:55.140Z" - }, - { - "x": 2, - "y": 474, - "type": "TEXT", - "value": "Rangely", - "last_modified": "2023-02-17T00:02:55.140Z" - }, - { - "x": 3, - "y": 474, - "type": "TEXT", - "value": "Rangely", - "last_modified": "2023-02-17T00:02:55.140Z" - }, - { - "x": 4, - "y": 474, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:55.140Z" - }, - { - "x": 5, - "y": 474, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.141Z" - }, - { - "x": 6, - "y": 474, - "type": "TEXT", - "value": "40.09469917", - "last_modified": "2023-02-17T00:02:55.141Z" - }, - { - "x": 7, - "y": 474, - "type": "TEXT", - "value": "-108.7612172", - "last_modified": "2023-02-17T00:02:55.141Z" - }, - { - "x": 0, - "y": 475, - "type": "TEXT", - "value": "472", - "last_modified": "2023-02-17T00:02:55.141Z" - }, - { - "x": 1, - "y": 475, - "type": "TEXT", - "value": "4V1", - "last_modified": "2023-02-17T00:02:55.141Z" - }, - { - "x": 2, - "y": 475, - "type": "TEXT", - "value": "Johnson", - "last_modified": "2023-02-17T00:02:55.141Z" - }, - { - "x": 3, - "y": 475, - "type": "TEXT", - "value": "Walsenburg", - "last_modified": "2023-02-17T00:02:55.142Z" - }, - { - "x": 4, - "y": 475, - "type": "TEXT", - "value": "CO", - "last_modified": "2023-02-17T00:02:55.142Z" - }, - { - "x": 5, - "y": 475, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.142Z" - }, - { - "x": 6, - "y": 475, - "type": "TEXT", - "value": "37.69640056", - "last_modified": "2023-02-17T00:02:55.142Z" - }, - { - "x": 7, - "y": 475, - "type": "TEXT", - "value": "-104.7838747", - "last_modified": "2023-02-17T00:02:55.142Z" - }, - { - "x": 0, - "y": 476, - "type": "TEXT", - "value": "473", - "last_modified": "2023-02-17T00:02:55.142Z" - }, - { - "x": 1, - "y": 476, - "type": "TEXT", - "value": "4V9", - "last_modified": "2023-02-17T00:02:55.143Z" - }, - { - "x": 2, - "y": 476, - "type": "TEXT", - "value": "Antelope County", - "last_modified": "2023-02-17T00:02:55.143Z" - }, - { - "x": 3, - "y": 476, - "type": "TEXT", - "value": "Neligh", - "last_modified": "2023-02-17T00:02:55.143Z" - }, - { - "x": 4, - "y": 476, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:55.143Z" - }, - { - "x": 5, - "y": 476, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.143Z" - }, - { - "x": 6, - "y": 476, - "type": "TEXT", - "value": "42.11222889", - "last_modified": "2023-02-17T00:02:55.143Z" - }, - { - "x": 7, - "y": 476, - "type": "TEXT", - "value": "-98.0386775", - "last_modified": "2023-02-17T00:02:55.144Z" - }, - { - "x": 0, - "y": 477, - "type": "TEXT", - "value": "474", - "last_modified": "2023-02-17T00:02:55.144Z" - }, - { - "x": 1, - "y": 477, - "type": "TEXT", - "value": "4W1", - "last_modified": "2023-02-17T00:02:55.144Z" - }, - { - "x": 2, - "y": 477, - "type": "TEXT", - "value": "Elizabethtown Municipal", - "last_modified": "2023-02-17T00:02:55.144Z" - }, - { - "x": 3, - "y": 477, - "type": "TEXT", - "value": "Elizabethtown", - "last_modified": "2023-02-17T00:02:55.144Z" - }, - { - "x": 4, - "y": 477, - "type": "TEXT", - "value": "NC", - "last_modified": "2023-02-17T00:02:55.144Z" - }, - { - "x": 5, - "y": 477, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.145Z" - }, - { - "x": 6, - "y": 477, - "type": "TEXT", - "value": "34.60183722", - "last_modified": "2023-02-17T00:02:55.145Z" - }, - { - "x": 7, - "y": 477, - "type": "TEXT", - "value": "-78.57973306", - "last_modified": "2023-02-17T00:02:55.145Z" - }, - { - "x": 0, - "y": 478, - "type": "TEXT", - "value": "475", - "last_modified": "2023-02-17T00:02:55.145Z" - }, - { - "x": 1, - "y": 478, - "type": "TEXT", - "value": "4Z4", - "last_modified": "2023-02-17T00:02:55.145Z" - }, - { - "x": 2, - "y": 478, - "type": "TEXT", - "value": "Holy Cross", - "last_modified": "2023-02-17T00:02:55.145Z" - }, - { - "x": 3, - "y": 478, - "type": "TEXT", - "value": "Holy Cross", - "last_modified": "2023-02-17T00:02:55.145Z" - }, - { - "x": 4, - "y": 478, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:55.146Z" - }, - { - "x": 5, - "y": 478, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.146Z" - }, - { - "x": 6, - "y": 478, - "type": "TEXT", - "value": "62.18829583", - "last_modified": "2023-02-17T00:02:55.146Z" - }, - { - "x": 7, - "y": 478, - "type": "TEXT", - "value": "-159.7749503", - "last_modified": "2023-02-17T00:02:55.146Z" - }, - { - "x": 0, - "y": 479, - "type": "TEXT", - "value": "476", - "last_modified": "2023-02-17T00:02:55.146Z" - }, - { - "x": 1, - "y": 479, - "type": "TEXT", - "value": "4Z7", - "last_modified": "2023-02-17T00:02:55.146Z" - }, - { - "x": 2, - "y": 479, - "type": "TEXT", - "value": "Hyder SPB", - "last_modified": "2023-02-17T00:02:55.147Z" - }, - { - "x": 3, - "y": 479, - "type": "TEXT", - "value": "Hyder", - "last_modified": "2023-02-17T00:02:55.147Z" - }, - { - "x": 4, - "y": 479, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:55.147Z" - }, - { - "x": 5, - "y": 479, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.147Z" - }, - { - "x": 6, - "y": 479, - "type": "TEXT", - "value": "55.90331972", - "last_modified": "2023-02-17T00:02:55.147Z" - }, - { - "x": 7, - "y": 479, - "type": "TEXT", - "value": "-130.0067031", - "last_modified": "2023-02-17T00:02:55.147Z" - }, - { - "x": 0, - "y": 480, - "type": "TEXT", - "value": "477", - "last_modified": "2023-02-17T00:02:55.147Z" - }, - { - "x": 1, - "y": 480, - "type": "TEXT", - "value": "50I", - "last_modified": "2023-02-17T00:02:55.148Z" - }, - { - "x": 2, - "y": 480, - "type": "TEXT", - "value": "Kentland Municipal", - "last_modified": "2023-02-17T00:02:55.148Z" - }, - { - "x": 3, - "y": 480, - "type": "TEXT", - "value": "Kentland", - "last_modified": "2023-02-17T00:02:55.148Z" - }, - { - "x": 4, - "y": 480, - "type": "TEXT", - "value": "IN", - "last_modified": "2023-02-17T00:02:55.148Z" - }, - { - "x": 5, - "y": 480, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.148Z" - }, - { - "x": 6, - "y": 480, - "type": "TEXT", - "value": "40.75873222", - "last_modified": "2023-02-17T00:02:55.148Z" - }, - { - "x": 7, - "y": 480, - "type": "TEXT", - "value": "-87.42821917", - "last_modified": "2023-02-17T00:02:55.149Z" - }, - { - "x": 0, - "y": 481, - "type": "TEXT", - "value": "478", - "last_modified": "2023-02-17T00:02:55.149Z" - }, - { - "x": 1, - "y": 481, - "type": "TEXT", - "value": "50J", - "last_modified": "2023-02-17T00:02:55.149Z" - }, - { - "x": 2, - "y": 481, - "type": "TEXT", - "value": "Berkeley County", - "last_modified": "2023-02-17T00:02:55.149Z" - }, - { - "x": 3, - "y": 481, - "type": "TEXT", - "value": "Moncks Corner", - "last_modified": "2023-02-17T00:02:55.149Z" - }, - { - "x": 4, - "y": 481, - "type": "TEXT", - "value": "SC", - "last_modified": "2023-02-17T00:02:55.149Z" - }, - { - "x": 5, - "y": 481, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.149Z" - }, - { - "x": 6, - "y": 481, - "type": "TEXT", - "value": "33.18605556", - "last_modified": "2023-02-17T00:02:55.150Z" - }, - { - "x": 7, - "y": 481, - "type": "TEXT", - "value": "-80.03563889", - "last_modified": "2023-02-17T00:02:55.150Z" - }, - { - "x": 0, - "y": 482, - "type": "TEXT", - "value": "479", - "last_modified": "2023-02-17T00:02:55.150Z" - }, - { - "x": 1, - "y": 482, - "type": "TEXT", - "value": "50K", - "last_modified": "2023-02-17T00:02:55.150Z" - }, - { - "x": 2, - "y": 482, - "type": "TEXT", - "value": "Pawnee City Municipal", - "last_modified": "2023-02-17T00:02:55.150Z" - }, - { - "x": 3, - "y": 482, - "type": "TEXT", - "value": "Pawnee City", - "last_modified": "2023-02-17T00:02:55.150Z" - }, - { - "x": 4, - "y": 482, - "type": "TEXT", - "value": "NE", - "last_modified": "2023-02-17T00:02:55.150Z" - }, - { - "x": 5, - "y": 482, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.151Z" - }, - { - "x": 6, - "y": 482, - "type": "TEXT", - "value": "40.11611111", - "last_modified": "2023-02-17T00:02:55.151Z" - }, - { - "x": 7, - "y": 482, - "type": "TEXT", - "value": "-96.19445278", - "last_modified": "2023-02-17T00:02:55.151Z" - }, - { - "x": 0, - "y": 483, - "type": "TEXT", - "value": "480", - "last_modified": "2023-02-17T00:02:55.151Z" - }, - { - "x": 1, - "y": 483, - "type": "TEXT", - "value": "50R", - "last_modified": "2023-02-17T00:02:55.151Z" - }, - { - "x": 2, - "y": 483, - "type": "TEXT", - "value": "Lockhart Municipal", - "last_modified": "2023-02-17T00:02:55.151Z" - }, - { - "x": 3, - "y": 483, - "type": "TEXT", - "value": "Lockhart", - "last_modified": "2023-02-17T00:02:55.151Z" - }, - { - "x": 4, - "y": 483, - "type": "TEXT", - "value": "TX", - "last_modified": "2023-02-17T00:02:55.152Z" - }, - { - "x": 5, - "y": 483, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.152Z" - }, - { - "x": 6, - "y": 483, - "type": "TEXT", - "value": "29.85033333", - "last_modified": "2023-02-17T00:02:55.152Z" - }, - { - "x": 7, - "y": 483, - "type": "TEXT", - "value": "-97.67241667", - "last_modified": "2023-02-17T00:02:55.152Z" - }, - { - "x": 0, - "y": 484, - "type": "TEXT", - "value": "481", - "last_modified": "2023-02-17T00:02:55.152Z" - }, - { - "x": 1, - "y": 484, - "type": "TEXT", - "value": "51D", - "last_modified": "2023-02-17T00:02:55.152Z" - }, - { - "x": 2, - "y": 484, - "type": "TEXT", - "value": "Edgeley Municipal", - "last_modified": "2023-02-17T00:02:55.152Z" - }, - { - "x": 3, - "y": 484, - "type": "TEXT", - "value": "Edgeley", - "last_modified": "2023-02-17T00:02:55.152Z" - }, - { - "x": 4, - "y": 484, - "type": "TEXT", - "value": "ND", - "last_modified": "2023-02-17T00:02:55.153Z" - }, - { - "x": 5, - "y": 484, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.153Z" - }, - { - "x": 6, - "y": 484, - "type": "TEXT", - "value": "46.34858333", - "last_modified": "2023-02-17T00:02:55.153Z" - }, - { - "x": 7, - "y": 484, - "type": "TEXT", - "value": "-98.73555556", - "last_modified": "2023-02-17T00:02:55.153Z" - }, - { - "x": 0, - "y": 485, - "type": "TEXT", - "value": "482", - "last_modified": "2023-02-17T00:02:55.153Z" - }, - { - "x": 1, - "y": 485, - "type": "TEXT", - "value": "51Z", - "last_modified": "2023-02-17T00:02:55.153Z" - }, - { - "x": 2, - "y": 485, - "type": "TEXT", - "value": "Minto (New)", - "last_modified": "2023-02-17T00:02:55.153Z" - }, - { - "x": 3, - "y": 485, - "type": "TEXT", - "value": "Minto", - "last_modified": "2023-02-17T00:02:55.154Z" - }, - { - "x": 4, - "y": 485, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:55.154Z" - }, - { - "x": 5, - "y": 485, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.154Z" - }, - { - "x": 6, - "y": 485, - "type": "TEXT", - "value": "65.14370889", - "last_modified": "2023-02-17T00:02:55.154Z" - }, - { - "x": 7, - "y": 485, - "type": "TEXT", - "value": "-149.3699647", - "last_modified": "2023-02-17T00:02:55.154Z" - }, - { - "x": 0, - "y": 486, - "type": "TEXT", - "value": "483", - "last_modified": "2023-02-17T00:02:55.154Z" - }, - { - "x": 1, - "y": 486, - "type": "TEXT", - "value": "52A", - "last_modified": "2023-02-17T00:02:55.154Z" - }, - { - "x": 2, - "y": 486, - "type": "TEXT", - "value": "Madison Municipal", - "last_modified": "2023-02-17T00:02:55.154Z" - }, - { - "x": 3, - "y": 486, - "type": "TEXT", - "value": "Madison", - "last_modified": "2023-02-17T00:02:55.155Z" - }, - { - "x": 4, - "y": 486, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:55.155Z" - }, - { - "x": 5, - "y": 486, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.155Z" - }, - { - "x": 6, - "y": 486, - "type": "TEXT", - "value": "33.61212528", - "last_modified": "2023-02-17T00:02:55.155Z" - }, - { - "x": 7, - "y": 486, - "type": "TEXT", - "value": "-83.46044333", - "last_modified": "2023-02-17T00:02:55.155Z" - }, - { - "x": 0, - "y": 487, - "type": "TEXT", - "value": "484", - "last_modified": "2023-02-17T00:02:55.155Z" - }, - { - "x": 1, - "y": 487, - "type": "TEXT", - "value": "52E", - "last_modified": "2023-02-17T00:02:55.155Z" - }, - { - "x": 2, - "y": 487, - "type": "TEXT", - "value": "Timberon", - "last_modified": "2023-02-17T00:02:55.156Z" - }, - { - "x": 3, - "y": 487, - "type": "TEXT", - "value": "Timberon", - "last_modified": "2023-02-17T00:02:55.156Z" - }, - { - "x": 4, - "y": 487, - "type": "TEXT", - "value": "NM", - "last_modified": "2023-02-17T00:02:55.156Z" - }, - { - "x": 5, - "y": 487, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.156Z" - }, - { - "x": 6, - "y": 487, - "type": "TEXT", - "value": "32.63388889", - "last_modified": "2023-02-17T00:02:55.156Z" - }, - { - "x": 7, - "y": 487, - "type": "TEXT", - "value": "-105.6863889", - "last_modified": "2023-02-17T00:02:55.156Z" - }, - { - "x": 0, - "y": 488, - "type": "TEXT", - "value": "485", - "last_modified": "2023-02-17T00:02:55.156Z" - }, - { - "x": 1, - "y": 488, - "type": "TEXT", - "value": "52J", - "last_modified": "2023-02-17T00:02:55.156Z" - }, - { - "x": 2, - "y": 488, - "type": "TEXT", - "value": "Lee County", - "last_modified": "2023-02-17T00:02:55.157Z" - }, - { - "x": 3, - "y": 488, - "type": "TEXT", - "value": "Bishopville", - "last_modified": "2023-02-17T00:02:55.157Z" - }, - { - "x": 4, - "y": 488, - "type": "TEXT", - "value": "SC", - "last_modified": "2023-02-17T00:02:55.157Z" - }, - { - "x": 5, - "y": 488, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.157Z" - }, - { - "x": 6, - "y": 488, - "type": "TEXT", - "value": "34.24459889", - "last_modified": "2023-02-17T00:02:55.157Z" - }, - { - "x": 7, - "y": 488, - "type": "TEXT", - "value": "-80.23729333", - "last_modified": "2023-02-17T00:02:55.157Z" - }, - { - "x": 0, - "y": 489, - "type": "TEXT", - "value": "486", - "last_modified": "2023-02-17T00:02:55.157Z" - }, - { - "x": 1, - "y": 489, - "type": "TEXT", - "value": "53A", - "last_modified": "2023-02-17T00:02:55.157Z" - }, - { - "x": 2, - "y": 489, - "type": "TEXT", - "value": "\"Dr. C.P. Savage", - "last_modified": "2023-02-17T00:02:55.158Z" - }, - { - "x": 3, - "y": 489, - "type": "TEXT", - "value": " Sr.\"", - "last_modified": "2023-02-17T00:02:55.158Z" - }, - { - "x": 4, - "y": 489, - "type": "TEXT", - "value": "Montezuma", - "last_modified": "2023-02-17T00:02:55.158Z" - }, - { - "x": 5, - "y": 489, - "type": "TEXT", - "value": "GA", - "last_modified": "2023-02-17T00:02:55.158Z" - }, - { - "x": 6, - "y": 489, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.158Z" - }, - { - "x": 7, - "y": 489, - "type": "TEXT", - "value": "32.302", - "last_modified": "2023-02-17T00:02:55.158Z" - }, - { - "x": 0, - "y": 490, - "type": "TEXT", - "value": "487", - "last_modified": "2023-02-17T00:02:55.158Z" - }, - { - "x": 1, - "y": 490, - "type": "TEXT", - "value": "53K", - "last_modified": "2023-02-17T00:02:55.158Z" - }, - { - "x": 2, - "y": 490, - "type": "TEXT", - "value": "Osage City Municipal", - "last_modified": "2023-02-17T00:02:55.159Z" - }, - { - "x": 3, - "y": 490, - "type": "TEXT", - "value": "Osage City", - "last_modified": "2023-02-17T00:02:55.159Z" - }, - { - "x": 4, - "y": 490, - "type": "TEXT", - "value": "KS", - "last_modified": "2023-02-17T00:02:55.159Z" - }, - { - "x": 5, - "y": 490, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.159Z" - }, - { - "x": 6, - "y": 490, - "type": "TEXT", - "value": "38.63334222", - "last_modified": "2023-02-17T00:02:55.159Z" - }, - { - "x": 7, - "y": 490, - "type": "TEXT", - "value": "-95.80859806", - "last_modified": "2023-02-17T00:02:55.159Z" - }, - { - "x": 0, - "y": 491, - "type": "TEXT", - "value": "488", - "last_modified": "2023-02-17T00:02:55.159Z" - }, - { - "x": 1, - "y": 491, - "type": "TEXT", - "value": "54J", - "last_modified": "2023-02-17T00:02:55.159Z" - }, - { - "x": 2, - "y": 491, - "type": "TEXT", - "value": "Defuniak Springs", - "last_modified": "2023-02-17T00:02:55.159Z" - }, - { - "x": 3, - "y": 491, - "type": "TEXT", - "value": "Defuniak Springs", - "last_modified": "2023-02-17T00:02:55.160Z" - }, - { - "x": 4, - "y": 491, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:55.160Z" - }, - { - "x": 5, - "y": 491, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.160Z" - }, - { - "x": 6, - "y": 491, - "type": "TEXT", - "value": "30.7313", - "last_modified": "2023-02-17T00:02:55.160Z" - }, - { - "x": 7, - "y": 491, - "type": "TEXT", - "value": "-86.15160833", - "last_modified": "2023-02-17T00:02:55.160Z" - }, - { - "x": 0, - "y": 492, - "type": "TEXT", - "value": "489", - "last_modified": "2023-02-17T00:02:55.160Z" - }, - { - "x": 1, - "y": 492, - "type": "TEXT", - "value": "55D", - "last_modified": "2023-02-17T00:02:55.160Z" - }, - { - "x": 2, - "y": 492, - "type": "TEXT", - "value": "Grayling Army Airfield", - "last_modified": "2023-02-17T00:02:55.160Z" - }, - { - "x": 3, - "y": 492, - "type": "TEXT", - "value": "Grayling", - "last_modified": "2023-02-17T00:02:55.161Z" - }, - { - "x": 4, - "y": 492, - "type": "TEXT", - "value": "MI", - "last_modified": "2023-02-17T00:02:55.161Z" - }, - { - "x": 5, - "y": 492, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.161Z" - }, - { - "x": 6, - "y": 492, - "type": "TEXT", - "value": "44.68032028", - "last_modified": "2023-02-17T00:02:55.161Z" - }, - { - "x": 7, - "y": 492, - "type": "TEXT", - "value": "-84.72886278", - "last_modified": "2023-02-17T00:02:55.161Z" - }, - { - "x": 0, - "y": 493, - "type": "TEXT", - "value": "490", - "last_modified": "2023-02-17T00:02:55.161Z" - }, - { - "x": 1, - "y": 493, - "type": "TEXT", - "value": "55J", - "last_modified": "2023-02-17T00:02:55.161Z" - }, - { - "x": 2, - "y": 493, - "type": "TEXT", - "value": "Fernandina Beach Municipal", - "last_modified": "2023-02-17T00:02:55.161Z" - }, - { - "x": 3, - "y": 493, - "type": "TEXT", - "value": "Fernandina Beach", - "last_modified": "2023-02-17T00:02:55.162Z" - }, - { - "x": 4, - "y": 493, - "type": "TEXT", - "value": "FL", - "last_modified": "2023-02-17T00:02:55.162Z" - }, - { - "x": 5, - "y": 493, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.162Z" - }, - { - "x": 6, - "y": 493, - "type": "TEXT", - "value": "30.61170083", - "last_modified": "2023-02-17T00:02:55.162Z" - }, - { - "x": 7, - "y": 493, - "type": "TEXT", - "value": "-81.462345", - "last_modified": "2023-02-17T00:02:55.162Z" - }, - { - "x": 0, - "y": 494, - "type": "TEXT", - "value": "491", - "last_modified": "2023-02-17T00:02:55.162Z" - }, - { - "x": 1, - "y": 494, - "type": "TEXT", - "value": "55S", - "last_modified": "2023-02-17T00:02:55.162Z" - }, - { - "x": 2, - "y": 494, - "type": "TEXT", - "value": "Packwood", - "last_modified": "2023-02-17T00:02:55.162Z" - }, - { - "x": 3, - "y": 494, - "type": "TEXT", - "value": "Packwood", - "last_modified": "2023-02-17T00:02:55.162Z" - }, - { - "x": 4, - "y": 494, - "type": "TEXT", - "value": "WA", - "last_modified": "2023-02-17T00:02:55.163Z" - }, - { - "x": 5, - "y": 494, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.163Z" - }, - { - "x": 6, - "y": 494, - "type": "TEXT", - "value": "46.60400083", - "last_modified": "2023-02-17T00:02:55.163Z" - }, - { - "x": 7, - "y": 494, - "type": "TEXT", - "value": "-121.6778664", - "last_modified": "2023-02-17T00:02:55.163Z" - }, - { - "x": 0, - "y": 495, - "type": "TEXT", - "value": "492", - "last_modified": "2023-02-17T00:02:55.163Z" - }, - { - "x": 1, - "y": 495, - "type": "TEXT", - "value": "56D", - "last_modified": "2023-02-17T00:02:55.163Z" - }, - { - "x": 2, - "y": 495, - "type": "TEXT", - "value": "Wyandot County", - "last_modified": "2023-02-17T00:02:55.163Z" - }, - { - "x": 3, - "y": 495, - "type": "TEXT", - "value": "Upper Sandusky", - "last_modified": "2023-02-17T00:02:55.163Z" - }, - { - "x": 4, - "y": 495, - "type": "TEXT", - "value": "OH", - "last_modified": "2023-02-17T00:02:55.163Z" - }, - { - "x": 5, - "y": 495, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.164Z" - }, - { - "x": 6, - "y": 495, - "type": "TEXT", - "value": "40.88336139", - "last_modified": "2023-02-17T00:02:55.164Z" - }, - { - "x": 7, - "y": 495, - "type": "TEXT", - "value": "-83.3145325", - "last_modified": "2023-02-17T00:02:55.164Z" - }, - { - "x": 0, - "y": 496, - "type": "TEXT", - "value": "493", - "last_modified": "2023-02-17T00:02:55.164Z" - }, - { - "x": 1, - "y": 496, - "type": "TEXT", - "value": "56M", - "last_modified": "2023-02-17T00:02:55.164Z" - }, - { - "x": 2, - "y": 496, - "type": "TEXT", - "value": "Warsaw Municipal", - "last_modified": "2023-02-17T00:02:55.164Z" - }, - { - "x": 3, - "y": 496, - "type": "TEXT", - "value": "Warsaw", - "last_modified": "2023-02-17T00:02:55.164Z" - }, - { - "x": 4, - "y": 496, - "type": "TEXT", - "value": "MO", - "last_modified": "2023-02-17T00:02:55.164Z" - }, - { - "x": 5, - "y": 496, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.165Z" - }, - { - "x": 6, - "y": 496, - "type": "TEXT", - "value": "38.34688889", - "last_modified": "2023-02-17T00:02:55.165Z" - }, - { - "x": 7, - "y": 496, - "type": "TEXT", - "value": "-93.345425", - "last_modified": "2023-02-17T00:02:55.165Z" - }, - { - "x": 0, - "y": 497, - "type": "TEXT", - "value": "494", - "last_modified": "2023-02-17T00:02:55.165Z" - }, - { - "x": 1, - "y": 497, - "type": "TEXT", - "value": "56S", - "last_modified": "2023-02-17T00:02:55.165Z" - }, - { - "x": 2, - "y": 497, - "type": "TEXT", - "value": "Seaside Municipal", - "last_modified": "2023-02-17T00:02:55.165Z" - }, - { - "x": 3, - "y": 497, - "type": "TEXT", - "value": "Seaside", - "last_modified": "2023-02-17T00:02:55.165Z" - }, - { - "x": 4, - "y": 497, - "type": "TEXT", - "value": "OR", - "last_modified": "2023-02-17T00:02:55.165Z" - }, - { - "x": 5, - "y": 497, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.165Z" - }, - { - "x": 6, - "y": 497, - "type": "TEXT", - "value": "46.01649694", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 7, - "y": 497, - "type": "TEXT", - "value": "-123.9054167", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 0, - "y": 498, - "type": "TEXT", - "value": "495", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 1, - "y": 498, - "type": "TEXT", - "value": "57B", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 2, - "y": 498, - "type": "TEXT", - "value": "Islesboro", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 3, - "y": 498, - "type": "TEXT", - "value": "Islesboro", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 4, - "y": 498, - "type": "TEXT", - "value": "ME", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 5, - "y": 498, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 6, - "y": 498, - "type": "TEXT", - "value": "44.30285556", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 7, - "y": 498, - "type": "TEXT", - "value": "-68.91058722", - "last_modified": "2023-02-17T00:02:55.166Z" - }, - { - "x": 0, - "y": 499, - "type": "TEXT", - "value": "496", - "last_modified": "2023-02-17T00:02:55.167Z" - }, - { - "x": 1, - "y": 499, - "type": "TEXT", - "value": "57C", - "last_modified": "2023-02-17T00:02:55.167Z" - }, - { - "x": 2, - "y": 499, - "type": "TEXT", - "value": "East Troy Municipal", - "last_modified": "2023-02-17T00:02:55.167Z" - }, - { - "x": 3, - "y": 499, - "type": "TEXT", - "value": "East Troy", - "last_modified": "2023-02-17T00:02:55.167Z" - }, - { - "x": 4, - "y": 499, - "type": "TEXT", - "value": "WI", - "last_modified": "2023-02-17T00:02:55.167Z" - }, - { - "x": 5, - "y": 499, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.167Z" - }, - { - "x": 6, - "y": 499, - "type": "TEXT", - "value": "42.79711111", - "last_modified": "2023-02-17T00:02:55.167Z" - }, - { - "x": 7, - "y": 499, - "type": "TEXT", - "value": "-88.3725", - "last_modified": "2023-02-17T00:02:55.167Z" - }, - { - "x": 0, - "y": 500, - "type": "TEXT", - "value": "497", - "last_modified": "2023-02-17T00:02:55.167Z" - }, - { - "x": 1, - "y": 500, - "type": "TEXT", - "value": "59B", - "last_modified": "2023-02-17T00:02:55.168Z" - }, - { - "x": 2, - "y": 500, - "type": "TEXT", - "value": "Newton", - "last_modified": "2023-02-17T00:02:55.168Z" - }, - { - "x": 3, - "y": 500, - "type": "TEXT", - "value": "Jackman", - "last_modified": "2023-02-17T00:02:55.168Z" - }, - { - "x": 4, - "y": 500, - "type": "TEXT", - "value": "ME", - "last_modified": "2023-02-17T00:02:55.168Z" - }, - { - "x": 5, - "y": 500, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.168Z" - }, - { - "x": 6, - "y": 500, - "type": "TEXT", - "value": "45.63199111", - "last_modified": "2023-02-17T00:02:55.168Z" - }, - { - "x": 7, - "y": 500, - "type": "TEXT", - "value": "-70.24728944", - "last_modified": "2023-02-17T00:02:55.168Z" - }, - { - "x": 0, - "y": 501, - "type": "TEXT", - "value": "498", - "last_modified": "2023-02-17T00:02:55.168Z" - }, - { - "x": 1, - "y": 501, - "type": "TEXT", - "value": "5A4", - "last_modified": "2023-02-17T00:02:55.168Z" - }, - { - "x": 2, - "y": 501, - "type": "TEXT", - "value": "Okolona Mun.-Richard M. Stovall", - "last_modified": "2023-02-17T00:02:55.169Z" - }, - { - "x": 3, - "y": 501, - "type": "TEXT", - "value": "Okolona", - "last_modified": "2023-02-17T00:02:55.169Z" - }, - { - "x": 4, - "y": 501, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:55.169Z" - }, - { - "x": 5, - "y": 501, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.169Z" - }, - { - "x": 6, - "y": 501, - "type": "TEXT", - "value": "34.01580528", - "last_modified": "2023-02-17T00:02:55.169Z" - }, - { - "x": 7, - "y": 501, - "type": "TEXT", - "value": "-88.72618944", - "last_modified": "2023-02-17T00:02:55.169Z" - }, - { - "x": 0, - "y": 502, - "type": "TEXT", - "value": "499", - "last_modified": "2023-02-17T00:02:55.169Z" - }, - { - "x": 1, - "y": 502, - "type": "TEXT", - "value": "5A6", - "last_modified": "2023-02-17T00:02:55.169Z" - }, - { - "x": 2, - "y": 502, - "type": "TEXT", - "value": "Winona-Montgomery County", - "last_modified": "2023-02-17T00:02:55.169Z" - }, - { - "x": 3, - "y": 502, - "type": "TEXT", - "value": "Winona", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 4, - "y": 502, - "type": "TEXT", - "value": "MS", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 5, - "y": 502, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 6, - "y": 502, - "type": "TEXT", - "value": "33.46540139", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 7, - "y": 502, - "type": "TEXT", - "value": "-89.72924806", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 0, - "y": 503, - "type": "TEXT", - "value": "500", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 1, - "y": 503, - "type": "TEXT", - "value": "5A8", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 2, - "y": 503, - "type": "TEXT", - "value": "Aleknagik", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 3, - "y": 503, - "type": "TEXT", - "value": "Aleknagik", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 4, - "y": 503, - "type": "TEXT", - "value": "AK", - "last_modified": "2023-02-17T00:02:55.170Z" - }, - { - "x": 5, - "y": 503, - "type": "TEXT", - "value": "USA", - "last_modified": "2023-02-17T00:02:55.171Z" - }, - { - "x": 6, - "y": 503, - "type": "TEXT", - "value": "59.28256167", - "last_modified": "2023-02-17T00:02:55.171Z" - }, - { - "x": 7, - "y": 503, - "type": "TEXT", - "value": "-158.6176725", - "last_modified": "2023-02-17T00:02:55.171Z" - }, - { - "x": 12, - "y": 23, - "type": "COMPUTED", - "value": "335", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 23, - "type": "COMPUTED", - "value": "3G7", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 23, - "type": "COMPUTED", - "value": "Williamson/Sodus", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 23, - "type": "COMPUTED", - "value": "Williamson", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 23, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 23, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 23, - "type": "COMPUTED", - "value": "43.23472222", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 23, - "type": "COMPUTED", - "value": "-77.12097222", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 24, - "type": "COMPUTED", - "value": "391", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 24, - "type": "COMPUTED", - "value": "44N", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 24, - "type": "COMPUTED", - "value": "Sky Acres", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 24, - "type": "COMPUTED", - "value": "Millbrook", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 24, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 24, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 24, - "type": "COMPUTED", - "value": "41.70742861", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 24, - "type": "COMPUTED", - "value": "-73.73802889", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 25, - "type": "COMPUTED", - "value": "397", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 25, - "type": "COMPUTED", - "value": "46N", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 25, - "type": "COMPUTED", - "value": "Sky Park", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 25, - "type": "COMPUTED", - "value": "Red Hook", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 25, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 25, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 25, - "type": "COMPUTED", - "value": "41.98458333", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 25, - "type": "COMPUTED", - "value": "-73.83596556", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 26, - "type": "COMPUTED", - "value": "418", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 26, - "type": "COMPUTED", - "value": "4B0", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 26, - "type": "COMPUTED", - "value": "South Albany", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 26, - "type": "COMPUTED", - "value": "South Bethlehem", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 26, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 26, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 26, - "type": "COMPUTED", - "value": "42.56072611", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 26, - "type": "COMPUTED", - "value": "-73.83395639", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 27, - "type": "COMPUTED", - "value": "419", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 27, - "type": "COMPUTED", - "value": "4B1", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 27, - "type": "COMPUTED", - "value": "Duanesburg", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 27, - "type": "COMPUTED", - "value": "Duanesburg", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 27, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 27, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 27, - "type": "COMPUTED", - "value": "42.75840889", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 27, - "type": "COMPUTED", - "value": "-74.13290472", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 28, - "type": "COMPUTED", - "value": "420", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 28, - "type": "COMPUTED", - "value": "4B6", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 28, - "type": "COMPUTED", - "value": "Ticonderoga Muni", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 28, - "type": "COMPUTED", - "value": "Ticonderoga", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 28, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 28, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 28, - "type": "COMPUTED", - "value": "43.87700278", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 28, - "type": "COMPUTED", - "value": "-73.41317639", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 29, - "type": "COMPUTED", - "value": "421", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 29, - "type": "COMPUTED", - "value": "4B7", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 29, - "type": "COMPUTED", - "value": "Schroon Lake", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 29, - "type": "COMPUTED", - "value": "Schroon Lake", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 29, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 29, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 29, - "type": "COMPUTED", - "value": "43.86256083", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 29, - "type": "COMPUTED", - "value": "-73.74262972", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 30, - "type": "COMPUTED", - "value": "430", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 30, - "type": "COMPUTED", - "value": "4G2", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 30, - "type": "COMPUTED", - "value": "Hamburg Inc.", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 30, - "type": "COMPUTED", - "value": "Hamburg", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 30, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 30, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 30, - "type": "COMPUTED", - "value": "42.7008925", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 30, - "type": "COMPUTED", - "value": "-78.91475694", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 12, - "y": 31, - "type": "COMPUTED", - "value": "432", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 13, - "y": 31, - "type": "COMPUTED", - "value": "4G6", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 14, - "y": 31, - "type": "COMPUTED", - "value": "Hornell Muni", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 15, - "y": 31, - "type": "COMPUTED", - "value": "Hornell", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 16, - "y": 31, - "type": "COMPUTED", - "value": "NY", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 17, - "y": 31, - "type": "COMPUTED", - "value": "USA", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 18, - "y": 31, - "type": "COMPUTED", - "value": "42.38214444", - "last_modified": "2023-02-17T00:03:07.616Z" - }, - { - "x": 19, - "y": 31, - "type": "COMPUTED", - "value": "-77.6821125", - "last_modified": "2023-02-17T00:03:07.616Z" - } - ], - "columns": [ - { - "id": 8, - "size": 23.099089593589838 - }, - { - "id": 9, - "size": 27.19140826340788 - }, - { - "id": 0, - "size": 53.841661695516095 - }, - { - "id": 1, - "size": 51.16415064981848 - }, - { - "id": 4, - "size": 47.350384272560746 - }, - { - "id": 5, - "size": 66.81890893378153 - }, - { - "id": 12, - "size": 55.477666679665276 - }, - { - "id": 13, - "size": 53.20090457660194 - }, - { - "id": 16, - "size": 57.63078821687259 - }, - { - "id": 17, - "size": 60.76811442136659 - } - ], - "rows": [], - "formats": [ - { - "x": 0, - "y": 0, - "bold": true - }, - { - "x": 0, - "y": 2, - "bold": true - }, - { - "x": 1, - "y": 2, - "bold": true - }, - { - "x": 2, - "y": 2, - "bold": true - }, - { - "x": 3, - "y": 2, - "bold": true - }, - { - "x": 4, - "y": 2, - "bold": true - }, - { - "x": 5, - "y": 2, - "bold": true - }, - { - "x": 6, - "y": 2, - "bold": true - }, - { - "x": 7, - "y": 2, - "bold": true - }, - { - "x": 11, - "y": 4, - "fillColor": "rgb(216, 255, 232)" - }, - { - "x": 10, - "y": 0, - "bold": true - }, - { - "x": 11, - "y": 2, - "bold": true - }, - { - "x": 12, - "y": 2, - "bold": true - }, - { - "x": 13, - "y": 2, - "bold": true - }, - { - "x": 14, - "y": 2, - "bold": true - }, - { - "x": 15, - "y": 2, - "bold": true - }, - { - "x": 16, - "y": 2, - "bold": true - }, - { - "x": 17, - "y": 2, - "bold": true - }, - { - "x": 18, - "y": 2, - "bold": true - }, - { - "x": 19, - "y": 2, - "bold": true - }, - { - "x": 10, - "y": 3, - "bold": true - }, - { - "x": 11, - "y": 3, - "fillColor": "rgb(216, 255, 232)" - }, - { - "x": 10, - "y": 4, - "bold": true - }, - { - "x": 10, - "y": 5, - "bold": true - }, - { - "x": 11, - "y": 5, - "bold": true, - "italic": true - }, - { - "x": 10, - "y": 8, - "bold": true - }, - { - "x": 12, - "y": 10, - "bold": true - }, - { - "x": 13, - "y": 10, - "bold": true - }, - { - "x": 14, - "y": 10, - "bold": true - }, - { - "x": 15, - "y": 10, - "bold": true - }, - { - "x": 16, - "y": 10, - "bold": true - }, - { - "x": 17, - "y": 10, - "bold": true - }, - { - "x": 18, - "y": 10, - "bold": true - }, - { - "x": 19, - "y": 10, - "bold": true - }, - { - "x": 11, - "y": 10, - "fillColor": "rgb(216, 255, 232)" - }, - { - "x": 10, - "y": 1, - "bold": true - } - ] - } - ], - "cell_dependency": "{\"22,2\":[[0,2],[0,2],[0,3],[0,3],[0,4],[0,4],[0,5],[0,5],[0,6],[0,6],[0,7],[0,7],[0,8],[0,8],[0,9],[0,9],[0,10],[0,10],[0,11],[0,11],[0,12],[0,12],[0,13],[0,13],[0,14],[0,14],[0,15],[0,15],[0,16],[0,16],[0,17],[0,17],[0,18],[0,18],[0,19],[0,19],[0,20],[0,20],[0,21],[0,21],[0,22],[0,22],[0,23],[0,23],[0,24],[0,24],[0,25],[0,25],[0,26],[0,26],[0,27],[0,27],[0,28],[0,28],[0,29],[0,29],[0,30],[0,30],[0,31],[0,31],[0,32],[0,32],[0,33],[0,33],[0,34],[0,34],[0,35],[0,35],[0,36],[0,36],[0,37],[0,37],[0,38],[0,38],[0,39],[0,39],[0,40],[0,40],[0,41],[0,41],[0,42],[0,42],[0,43],[0,43],[0,44],[0,44],[0,45],[0,45],[0,46],[0,46],[0,47],[0,47],[0,48],[0,48],[0,49],[0,49],[0,50],[0,50],[0,51],[0,51],[0,52],[0,52],[0,53],[0,53],[0,54],[0,54],[0,55],[0,55],[0,56],[0,56],[0,57],[0,57],[0,58],[0,58],[0,59],[0,59],[0,60],[0,60],[0,61],[0,61],[0,62],[0,62],[0,63],[0,63],[0,64],[0,64],[0,65],[0,65],[0,66],[0,66],[0,67],[0,67],[0,68],[0,68],[0,69],[0,69],[0,70],[0,70],[0,71],[0,71],[0,72],[0,72],[0,73],[0,73],[0,74],[0,74],[0,75],[0,75],[0,76],[0,76],[0,77],[0,77],[0,78],[0,78],[0,79],[0,79],[0,80],[0,80],[0,81],[0,81],[0,82],[0,82],[0,83],[0,83],[0,84],[0,84],[0,85],[0,85],[0,86],[0,86],[0,87],[0,87],[0,88],[0,88],[0,89],[0,89],[0,90],[0,90],[0,91],[0,91],[0,92],[0,92],[0,93],[0,93],[0,94],[0,94],[0,95],[0,95],[0,96],[0,96],[0,97],[0,97],[0,98],[0,98],[0,99],[0,99],[0,100],[0,100],[0,101],[0,101],[0,102],[0,102],[0,103],[0,103],[0,104],[0,104],[0,105],[0,105],[0,106],[0,106],[0,107],[0,107],[0,108],[0,108],[0,109],[0,109],[0,110],[0,110],[0,111],[0,111],[0,112],[0,112],[0,113],[0,113],[0,114],[0,114],[0,115],[0,115],[0,116],[0,116],[0,117],[0,117],[0,118],[0,118],[0,119],[0,119],[0,120],[0,120],[0,121],[0,121],[0,122],[0,122],[0,123],[0,123],[0,124],[0,124],[0,125],[0,125],[0,126],[0,126],[0,127],[0,127],[0,128],[0,128],[0,129],[0,129],[0,130],[0,130],[0,131],[0,131],[0,132],[0,132],[0,133],[0,133],[0,134],[0,134],[0,135],[0,135],[0,136],[0,136],[0,137],[0,137],[0,138],[0,138],[0,139],[0,139],[0,140],[0,140],[0,141],[0,141],[0,142],[0,142],[0,143],[0,143],[0,144],[0,144],[0,145],[0,145],[0,146],[0,146],[0,147],[0,147],[0,148],[0,148],[0,149],[0,149],[0,150],[0,150],[0,151],[0,151],[0,152],[0,152],[0,153],[0,153],[0,154],[0,154],[0,155],[0,155],[0,156],[0,156],[0,157],[0,157],[0,158],[0,158],[0,159],[0,159],[0,160],[0,160],[0,161],[0,161],[0,162],[0,162],[0,163],[0,163],[0,164],[0,164],[0,165],[0,165],[0,166],[0,166],[0,167],[0,167],[0,168],[0,168],[0,169],[0,169],[0,170],[0,170],[0,171],[0,171],[0,172],[0,172],[0,173],[0,173],[0,174],[0,174],[0,175],[0,175],[0,176],[0,176],[0,177],[0,177],[0,178],[0,178],[0,179],[0,179],[0,180],[0,180],[0,181],[0,181],[0,182],[0,182],[0,183],[0,183],[0,184],[0,184],[0,185],[0,185],[0,186],[0,186],[0,187],[0,187],[0,188],[0,188],[0,189],[0,189],[0,190],[0,190],[0,191],[0,191],[0,192],[0,192],[0,193],[0,193],[0,194],[0,194],[0,195],[0,195],[0,196],[0,196],[0,197],[0,197],[0,198],[0,198],[0,199],[0,199],[0,200],[0,200],[0,201],[0,201],[0,202],[0,202],[0,203],[0,203],[0,204],[0,204],[0,205],[0,205],[0,206],[0,206],[0,207],[0,207],[0,208],[0,208],[0,209],[0,209],[0,210],[0,210],[0,211],[0,211],[0,212],[0,212],[0,213],[0,213],[0,214],[0,214],[0,215],[0,215],[0,216],[0,216],[0,217],[0,217],[0,218],[0,218],[0,219],[0,219],[0,220],[0,220],[0,221],[0,221],[0,222],[0,222],[0,223],[0,223],[0,224],[0,224],[0,225],[0,225],[0,226],[0,226],[0,227],[0,227],[0,228],[0,228],[0,229],[0,229],[0,230],[0,230],[0,231],[0,231],[0,232],[0,232],[0,233],[0,233],[0,234],[0,234],[0,235],[0,235],[0,236],[0,236],[0,237],[0,237],[0,238],[0,238],[0,239],[0,239],[0,240],[0,240],[0,241],[0,241],[0,242],[0,242],[0,243],[0,243],[0,244],[0,244],[0,245],[0,245],[0,246],[0,246],[0,247],[0,247],[0,248],[0,248],[0,249],[0,249],[0,250],[0,250],[0,251],[0,251],[0,252],[0,252],[0,253],[0,253],[0,254],[0,254],[0,255],[0,255],[0,256],[0,256],[0,257],[0,257],[0,258],[0,258],[0,259],[0,259],[0,260],[0,260],[0,261],[0,261],[0,262],[0,262],[0,263],[0,263],[0,264],[0,264],[0,265],[0,265],[0,266],[0,266],[0,267],[0,267],[0,268],[0,268],[0,269],[0,269],[0,270],[0,270],[0,271],[0,271],[0,272],[0,272],[0,273],[0,273],[0,274],[0,274],[0,275],[0,275],[0,276],[0,276],[0,277],[0,277],[0,278],[0,278],[0,279],[0,279],[0,280],[0,280],[0,281],[0,281],[0,282],[0,282],[0,283],[0,283],[0,284],[0,284],[0,285],[0,285],[0,286],[0,286],[0,287],[0,287],[0,288],[0,288],[0,289],[0,289],[0,290],[0,290],[0,291],[0,291],[0,292],[0,292],[0,293],[0,293],[0,294],[0,294],[0,295],[0,295],[0,296],[0,296],[0,297],[0,297],[0,298],[0,298],[0,299],[0,299],[0,300],[0,300],[0,301],[0,301],[0,302],[0,302],[0,303],[0,303],[0,304],[0,304],[0,305],[0,305],[0,306],[0,306],[0,307],[0,307],[0,308],[0,308],[0,309],[0,309],[0,310],[0,310],[0,311],[0,311],[0,312],[0,312],[0,313],[0,313],[0,314],[0,314],[0,315],[0,315],[0,316],[0,316],[0,317],[0,317],[0,318],[0,318],[0,319],[0,319],[0,320],[0,320],[0,321],[0,321],[0,322],[0,322],[0,323],[0,323],[0,324],[0,324],[0,325],[0,325],[0,326],[0,326],[0,327],[0,327],[0,328],[0,328],[0,329],[0,329],[0,330],[0,330],[0,331],[0,331],[0,332],[0,332],[0,333],[0,333],[0,334],[0,334],[0,335],[0,335],[0,336],[0,336],[0,337],[0,337],[0,338],[0,338],[0,339],[0,339],[0,340],[0,340],[0,341],[0,341],[0,342],[0,342],[0,343],[0,343],[0,344],[0,344],[0,345],[0,345],[0,346],[0,346],[0,347],[0,347],[0,348],[0,348],[0,349],[0,349],[0,350],[0,350],[0,351],[0,351],[0,352],[0,352],[0,353],[0,353],[0,354],[0,354],[0,355],[0,355],[0,356],[0,356],[0,357],[0,357],[0,358],[0,358],[0,359],[0,359],[0,360],[0,360],[0,361],[0,361],[0,362],[0,362],[0,363],[0,363],[0,364],[0,364],[0,365],[0,365],[0,366],[0,366],[0,367],[0,367],[0,368],[0,368],[0,369],[0,369],[0,370],[0,370],[0,371],[0,371],[0,372],[0,372],[0,373],[0,373],[0,374],[0,374],[0,375],[0,375],[0,376],[0,376],[0,377],[0,377],[0,378],[0,378],[0,379],[0,379],[0,380],[0,380],[0,381],[0,381],[0,382],[0,382],[0,383],[0,383],[0,384],[0,384],[0,385],[0,385],[0,386],[0,386],[0,387],[0,387],[0,388],[0,388],[0,389],[0,389],[0,390],[0,390],[0,391],[0,391],[0,392],[0,392],[0,393],[0,393],[0,394],[0,394],[0,395],[0,395],[0,396],[0,396],[0,397],[0,397],[0,398],[0,398],[0,399],[0,399],[0,400],[0,400],[0,401],[0,401],[0,402],[0,402],[0,403],[0,403],[0,404],[0,404],[0,405],[0,405],[0,406],[0,406],[0,407],[0,407],[0,408],[0,408],[0,409],[0,409],[0,410],[0,410],[0,411],[0,411],[0,412],[0,412],[0,413],[0,413],[0,414],[0,414],[0,415],[0,415],[0,416],[0,416],[0,417],[0,417],[0,418],[0,418],[0,419],[0,419],[0,420],[0,420],[0,421],[0,421],[0,422],[0,422],[0,423],[0,423],[0,424],[0,424],[0,425],[0,425],[0,426],[0,426],[0,427],[0,427],[0,428],[0,428],[0,429],[0,429],[0,430],[0,430],[0,431],[0,431],[0,432],[0,432],[0,433],[0,433],[0,434],[0,434],[0,435],[0,435],[0,436],[0,436],[0,437],[0,437],[0,438],[0,438],[0,439],[0,439],[0,440],[0,440],[0,441],[0,441],[0,442],[0,442],[0,443],[0,443],[0,444],[0,444],[0,445],[0,445],[0,446],[0,446],[0,447],[0,447],[0,448],[0,448],[0,449],[0,449],[0,450],[0,450],[0,451],[0,451],[0,452],[0,452],[0,453],[0,453],[0,454],[0,454],[0,455],[0,455],[0,456],[0,456],[0,457],[0,457],[0,458],[0,458],[0,459],[0,459],[0,460],[0,460],[0,461],[0,461],[0,462],[0,462],[0,463],[0,463],[0,464],[0,464],[0,465],[0,465],[0,466],[0,466],[0,467],[0,467],[0,468],[0,468],[0,469],[0,469],[0,470],[0,470],[0,471],[0,471],[0,472],[0,472],[0,473],[0,473],[0,474],[0,474],[0,475],[0,475],[0,476],[0,476],[0,477],[0,477],[0,478],[0,478],[0,479],[0,479],[0,480],[0,480],[0,481],[0,481],[0,482],[0,482],[0,483],[0,483],[0,484],[0,484],[0,485],[0,485],[0,486],[0,486],[0,487],[0,487],[0,488],[0,488],[0,489],[0,489],[0,490],[0,490],[0,491],[0,491],[0,492],[0,492],[0,493],[0,493],[0,494],[0,494],[0,495],[0,495],[0,496],[0,496],[0,497],[0,497],[0,498],[0,498],[0,499],[0,499],[0,500],[0,500],[1,2],[1,2],[1,3],[1,3],[1,4],[1,4],[1,5],[1,5],[1,6],[1,6],[1,7],[1,7],[1,8],[1,8],[1,9],[1,9],[1,10],[1,10],[1,11],[1,11],[1,12],[1,12],[1,13],[1,13],[1,14],[1,14],[1,15],[1,15],[1,16],[1,16],[1,17],[1,17],[1,18],[1,18],[1,19],[1,19],[1,20],[1,20],[1,21],[1,21],[1,22],[1,22],[1,23],[1,23],[1,24],[1,24],[1,25],[1,25],[1,26],[1,26],[1,27],[1,27],[1,28],[1,28],[1,29],[1,29],[1,30],[1,30],[1,31],[1,31],[1,32],[1,32],[1,33],[1,33],[1,34],[1,34],[1,35],[1,35],[1,36],[1,36],[1,37],[1,37],[1,38],[1,38],[1,39],[1,39],[1,40],[1,40],[1,41],[1,41],[1,42],[1,42],[1,43],[1,43],[1,44],[1,44],[1,45],[1,45],[1,46],[1,46],[1,47],[1,47],[1,48],[1,48],[1,49],[1,49],[1,50],[1,50],[1,51],[1,51],[1,52],[1,52],[1,53],[1,53],[1,54],[1,54],[1,55],[1,55],[1,56],[1,56],[1,57],[1,57],[1,58],[1,58],[1,59],[1,59],[1,60],[1,60],[1,61],[1,61],[1,62],[1,62],[1,63],[1,63],[1,64],[1,64],[1,65],[1,65],[1,66],[1,66],[1,67],[1,67],[1,68],[1,68],[1,69],[1,69],[1,70],[1,70],[1,71],[1,71],[1,72],[1,72],[1,73],[1,73],[1,74],[1,74],[1,75],[1,75],[1,76],[1,76],[1,77],[1,77],[1,78],[1,78],[1,79],[1,79],[1,80],[1,80],[1,81],[1,81],[1,82],[1,82],[1,83],[1,83],[1,84],[1,84],[1,85],[1,85],[1,86],[1,86],[1,87],[1,87],[1,88],[1,88],[1,89],[1,89],[1,90],[1,90],[1,91],[1,91],[1,92],[1,92],[1,93],[1,93],[1,94],[1,94],[1,95],[1,95],[1,96],[1,96],[1,97],[1,97],[1,98],[1,98],[1,99],[1,99],[1,100],[1,100],[1,101],[1,101],[1,102],[1,102],[1,103],[1,103],[1,104],[1,104],[1,105],[1,105],[1,106],[1,106],[1,107],[1,107],[1,108],[1,108],[1,109],[1,109],[1,110],[1,110],[1,111],[1,111],[1,112],[1,112],[1,113],[1,113],[1,114],[1,114],[1,115],[1,115],[1,116],[1,116],[1,117],[1,117],[1,118],[1,118],[1,119],[1,119],[1,120],[1,120],[1,121],[1,121],[1,122],[1,122],[1,123],[1,123],[1,124],[1,124],[1,125],[1,125],[1,126],[1,126],[1,127],[1,127],[1,128],[1,128],[1,129],[1,129],[1,130],[1,130],[1,131],[1,131],[1,132],[1,132],[1,133],[1,133],[1,134],[1,134],[1,135],[1,135],[1,136],[1,136],[1,137],[1,137],[1,138],[1,138],[1,139],[1,139],[1,140],[1,140],[1,141],[1,141],[1,142],[1,142],[1,143],[1,143],[1,144],[1,144],[1,145],[1,145],[1,146],[1,146],[1,147],[1,147],[1,148],[1,148],[1,149],[1,149],[1,150],[1,150],[1,151],[1,151],[1,152],[1,152],[1,153],[1,153],[1,154],[1,154],[1,155],[1,155],[1,156],[1,156],[1,157],[1,157],[1,158],[1,158],[1,159],[1,159],[1,160],[1,160],[1,161],[1,161],[1,162],[1,162],[1,163],[1,163],[1,164],[1,164],[1,165],[1,165],[1,166],[1,166],[1,167],[1,167],[1,168],[1,168],[1,169],[1,169],[1,170],[1,170],[1,171],[1,171],[1,172],[1,172],[1,173],[1,173],[1,174],[1,174],[1,175],[1,175],[1,176],[1,176],[1,177],[1,177],[1,178],[1,178],[1,179],[1,179],[1,180],[1,180],[1,181],[1,181],[1,182],[1,182],[1,183],[1,183],[1,184],[1,184],[1,185],[1,185],[1,186],[1,186],[1,187],[1,187],[1,188],[1,188],[1,189],[1,189],[1,190],[1,190],[1,191],[1,191],[1,192],[1,192],[1,193],[1,193],[1,194],[1,194],[1,195],[1,195],[1,196],[1,196],[1,197],[1,197],[1,198],[1,198],[1,199],[1,199],[1,200],[1,200],[1,201],[1,201],[1,202],[1,202],[1,203],[1,203],[1,204],[1,204],[1,205],[1,205],[1,206],[1,206],[1,207],[1,207],[1,208],[1,208],[1,209],[1,209],[1,210],[1,210],[1,211],[1,211],[1,212],[1,212],[1,213],[1,213],[1,214],[1,214],[1,215],[1,215],[1,216],[1,216],[1,217],[1,217],[1,218],[1,218],[1,219],[1,219],[1,220],[1,220],[1,221],[1,221],[1,222],[1,222],[1,223],[1,223],[1,224],[1,224],[1,225],[1,225],[1,226],[1,226],[1,227],[1,227],[1,228],[1,228],[1,229],[1,229],[1,230],[1,230],[1,231],[1,231],[1,232],[1,232],[1,233],[1,233],[1,234],[1,234],[1,235],[1,235],[1,236],[1,236],[1,237],[1,237],[1,238],[1,238],[1,239],[1,239],[1,240],[1,240],[1,241],[1,241],[1,242],[1,242],[1,243],[1,243],[1,244],[1,244],[1,245],[1,245],[1,246],[1,246],[1,247],[1,247],[1,248],[1,248],[1,249],[1,249],[1,250],[1,250],[1,251],[1,251],[1,252],[1,252],[1,253],[1,253],[1,254],[1,254],[1,255],[1,255],[1,256],[1,256],[1,257],[1,257],[1,258],[1,258],[1,259],[1,259],[1,260],[1,260],[1,261],[1,261],[1,262],[1,262],[1,263],[1,263],[1,264],[1,264],[1,265],[1,265],[1,266],[1,266],[1,267],[1,267],[1,268],[1,268],[1,269],[1,269],[1,270],[1,270],[1,271],[1,271],[1,272],[1,272],[1,273],[1,273],[1,274],[1,274],[1,275],[1,275],[1,276],[1,276],[1,277],[1,277],[1,278],[1,278],[1,279],[1,279],[1,280],[1,280],[1,281],[1,281],[1,282],[1,282],[1,283],[1,283],[1,284],[1,284],[1,285],[1,285],[1,286],[1,286],[1,287],[1,287],[1,288],[1,288],[1,289],[1,289],[1,290],[1,290],[1,291],[1,291],[1,292],[1,292],[1,293],[1,293],[1,294],[1,294],[1,295],[1,295],[1,296],[1,296],[1,297],[1,297],[1,298],[1,298],[1,299],[1,299],[1,300],[1,300],[1,301],[1,301],[1,302],[1,302],[1,303],[1,303],[1,304],[1,304],[1,305],[1,305],[1,306],[1,306],[1,307],[1,307],[1,308],[1,308],[1,309],[1,309],[1,310],[1,310],[1,311],[1,311],[1,312],[1,312],[1,313],[1,313],[1,314],[1,314],[1,315],[1,315],[1,316],[1,316],[1,317],[1,317],[1,318],[1,318],[1,319],[1,319],[1,320],[1,320],[1,321],[1,321],[1,322],[1,322],[1,323],[1,323],[1,324],[1,324],[1,325],[1,325],[1,326],[1,326],[1,327],[1,327],[1,328],[1,328],[1,329],[1,329],[1,330],[1,330],[1,331],[1,331],[1,332],[1,332],[1,333],[1,333],[1,334],[1,334],[1,335],[1,335],[1,336],[1,336],[1,337],[1,337],[1,338],[1,338],[1,339],[1,339],[1,340],[1,340],[1,341],[1,341],[1,342],[1,342],[1,343],[1,343],[1,344],[1,344],[1,345],[1,345],[1,346],[1,346],[1,347],[1,347],[1,348],[1,348],[1,349],[1,349],[1,350],[1,350],[1,351],[1,351],[1,352],[1,352],[1,353],[1,353],[1,354],[1,354],[1,355],[1,355],[1,356],[1,356],[1,357],[1,357],[1,358],[1,358],[1,359],[1,359],[1,360],[1,360],[1,361],[1,361],[1,362],[1,362],[1,363],[1,363],[1,364],[1,364],[1,365],[1,365],[1,366],[1,366],[1,367],[1,367],[1,368],[1,368],[1,369],[1,369],[1,370],[1,370],[1,371],[1,371],[1,372],[1,372],[1,373],[1,373],[1,374],[1,374],[1,375],[1,375],[1,376],[1,376],[1,377],[1,377],[1,378],[1,378],[1,379],[1,379],[1,380],[1,380],[1,381],[1,381],[1,382],[1,382],[1,383],[1,383],[1,384],[1,384],[1,385],[1,385],[1,386],[1,386],[1,387],[1,387],[1,388],[1,388],[1,389],[1,389],[1,390],[1,390],[1,391],[1,391],[1,392],[1,392],[1,393],[1,393],[1,394],[1,394],[1,395],[1,395],[1,396],[1,396],[1,397],[1,397],[1,398],[1,398],[1,399],[1,399],[1,400],[1,400],[1,401],[1,401],[1,402],[1,402],[1,403],[1,403],[1,404],[1,404],[1,405],[1,405],[1,406],[1,406],[1,407],[1,407],[1,408],[1,408],[1,409],[1,409],[1,410],[1,410],[1,411],[1,411],[1,412],[1,412],[1,413],[1,413],[1,414],[1,414],[1,415],[1,415],[1,416],[1,416],[1,417],[1,417],[1,418],[1,418],[1,419],[1,419],[1,420],[1,420],[1,421],[1,421],[1,422],[1,422],[1,423],[1,423],[1,424],[1,424],[1,425],[1,425],[1,426],[1,426],[1,427],[1,427],[1,428],[1,428],[1,429],[1,429],[1,430],[1,430],[1,431],[1,431],[1,432],[1,432],[1,433],[1,433],[1,434],[1,434],[1,435],[1,435],[1,436],[1,436],[1,437],[1,437],[1,438],[1,438],[1,439],[1,439],[1,440],[1,440],[1,441],[1,441],[1,442],[1,442],[1,443],[1,443],[1,444],[1,444],[1,445],[1,445],[1,446],[1,446],[1,447],[1,447],[1,448],[1,448],[1,449],[1,449],[1,450],[1,450],[1,451],[1,451],[1,452],[1,452],[1,453],[1,453],[1,454],[1,454],[1,455],[1,455],[1,456],[1,456],[1,457],[1,457],[1,458],[1,458],[1,459],[1,459],[1,460],[1,460],[1,461],[1,461],[1,462],[1,462],[1,463],[1,463],[1,464],[1,464],[1,465],[1,465],[1,466],[1,466],[1,467],[1,467],[1,468],[1,468],[1,469],[1,469],[1,470],[1,470],[1,471],[1,471],[1,472],[1,472],[1,473],[1,473],[1,474],[1,474],[1,475],[1,475],[1,476],[1,476],[1,477],[1,477],[1,478],[1,478],[1,479],[1,479],[1,480],[1,480],[1,481],[1,481],[1,482],[1,482],[1,483],[1,483],[1,484],[1,484],[1,485],[1,485],[1,486],[1,486],[1,487],[1,487],[1,488],[1,488],[1,489],[1,489],[1,490],[1,490],[1,491],[1,491],[1,492],[1,492],[1,493],[1,493],[1,494],[1,494],[1,495],[1,495],[1,496],[1,496],[1,497],[1,497],[1,498],[1,498],[1,499],[1,499],[1,500],[1,500],[2,2],[2,2],[2,3],[2,3],[2,4],[2,4],[2,5],[2,5],[2,6],[2,6],[2,7],[2,7],[2,8],[2,8],[2,9],[2,9],[2,10],[2,10],[2,11],[2,11],[2,12],[2,12],[2,13],[2,13],[2,14],[2,14],[2,15],[2,15],[2,16],[2,16],[2,17],[2,17],[2,18],[2,18],[2,19],[2,19],[2,20],[2,20],[2,21],[2,21],[2,22],[2,22],[2,23],[2,23],[2,24],[2,24],[2,25],[2,25],[2,26],[2,26],[2,27],[2,27],[2,28],[2,28],[2,29],[2,29],[2,30],[2,30],[2,31],[2,31],[2,32],[2,32],[2,33],[2,33],[2,34],[2,34],[2,35],[2,35],[2,36],[2,36],[2,37],[2,37],[2,38],[2,38],[2,39],[2,39],[2,40],[2,40],[2,41],[2,41],[2,42],[2,42],[2,43],[2,43],[2,44],[2,44],[2,45],[2,45],[2,46],[2,46],[2,47],[2,47],[2,48],[2,48],[2,49],[2,49],[2,50],[2,50],[2,51],[2,51],[2,52],[2,52],[2,53],[2,53],[2,54],[2,54],[2,55],[2,55],[2,56],[2,56],[2,57],[2,57],[2,58],[2,58],[2,59],[2,59],[2,60],[2,60],[2,61],[2,61],[2,62],[2,62],[2,63],[2,63],[2,64],[2,64],[2,65],[2,65],[2,66],[2,66],[2,67],[2,67],[2,68],[2,68],[2,69],[2,69],[2,70],[2,70],[2,71],[2,71],[2,72],[2,72],[2,73],[2,73],[2,74],[2,74],[2,75],[2,75],[2,76],[2,76],[2,77],[2,77],[2,78],[2,78],[2,79],[2,79],[2,80],[2,80],[2,81],[2,81],[2,82],[2,82],[2,83],[2,83],[2,84],[2,84],[2,85],[2,85],[2,86],[2,86],[2,87],[2,87],[2,88],[2,88],[2,89],[2,89],[2,90],[2,90],[2,91],[2,91],[2,92],[2,92],[2,93],[2,93],[2,94],[2,94],[2,95],[2,95],[2,96],[2,96],[2,97],[2,97],[2,98],[2,98],[2,99],[2,99],[2,100],[2,100],[2,101],[2,101],[2,102],[2,102],[2,103],[2,103],[2,104],[2,104],[2,105],[2,105],[2,106],[2,106],[2,107],[2,107],[2,108],[2,108],[2,109],[2,109],[2,110],[2,110],[2,111],[2,111],[2,112],[2,112],[2,113],[2,113],[2,114],[2,114],[2,115],[2,115],[2,116],[2,116],[2,117],[2,117],[2,118],[2,118],[2,119],[2,119],[2,120],[2,120],[2,121],[2,121],[2,122],[2,122],[2,123],[2,123],[2,124],[2,124],[2,125],[2,125],[2,126],[2,126],[2,127],[2,127],[2,128],[2,128],[2,129],[2,129],[2,130],[2,130],[2,131],[2,131],[2,132],[2,132],[2,133],[2,133],[2,134],[2,134],[2,135],[2,135],[2,136],[2,136],[2,137],[2,137],[2,138],[2,138],[2,139],[2,139],[2,140],[2,140],[2,141],[2,141],[2,142],[2,142],[2,143],[2,143],[2,144],[2,144],[2,145],[2,145],[2,146],[2,146],[2,147],[2,147],[2,148],[2,148],[2,149],[2,149],[2,150],[2,150],[2,151],[2,151],[2,152],[2,152],[2,153],[2,153],[2,154],[2,154],[2,155],[2,155],[2,156],[2,156],[2,157],[2,157],[2,158],[2,158],[2,159],[2,159],[2,160],[2,160],[2,161],[2,161],[2,162],[2,162],[2,163],[2,163],[2,164],[2,164],[2,165],[2,165],[2,166],[2,166],[2,167],[2,167],[2,168],[2,168],[2,169],[2,169],[2,170],[2,170],[2,171],[2,171],[2,172],[2,172],[2,173],[2,173],[2,174],[2,174],[2,175],[2,175],[2,176],[2,176],[2,177],[2,177],[2,178],[2,178],[2,179],[2,179],[2,180],[2,180],[2,181],[2,181],[2,182],[2,182],[2,183],[2,183],[2,184],[2,184],[2,185],[2,185],[2,186],[2,186],[2,187],[2,187],[2,188],[2,188],[2,189],[2,189],[2,190],[2,190],[2,191],[2,191],[2,192],[2,192],[2,193],[2,193],[2,194],[2,194],[2,195],[2,195],[2,196],[2,196],[2,197],[2,197],[2,198],[2,198],[2,199],[2,199],[2,200],[2,200],[2,201],[2,201],[2,202],[2,202],[2,203],[2,203],[2,204],[2,204],[2,205],[2,205],[2,206],[2,206],[2,207],[2,207],[2,208],[2,208],[2,209],[2,209],[2,210],[2,210],[2,211],[2,211],[2,212],[2,212],[2,213],[2,213],[2,214],[2,214],[2,215],[2,215],[2,216],[2,216],[2,217],[2,217],[2,218],[2,218],[2,219],[2,219],[2,220],[2,220],[2,221],[2,221],[2,222],[2,222],[2,223],[2,223],[2,224],[2,224],[2,225],[2,225],[2,226],[2,226],[2,227],[2,227],[2,228],[2,228],[2,229],[2,229],[2,230],[2,230],[2,231],[2,231],[2,232],[2,232],[2,233],[2,233],[2,234],[2,234],[2,235],[2,235],[2,236],[2,236],[2,237],[2,237],[2,238],[2,238],[2,239],[2,239],[2,240],[2,240],[2,241],[2,241],[2,242],[2,242],[2,243],[2,243],[2,244],[2,244],[2,245],[2,245],[2,246],[2,246],[2,247],[2,247],[2,248],[2,248],[2,249],[2,249],[2,250],[2,250],[2,251],[2,251],[2,252],[2,252],[2,253],[2,253],[2,254],[2,254],[2,255],[2,255],[2,256],[2,256],[2,257],[2,257],[2,258],[2,258],[2,259],[2,259],[2,260],[2,260],[2,261],[2,261],[2,262],[2,262],[2,263],[2,263],[2,264],[2,264],[2,265],[2,265],[2,266],[2,266],[2,267],[2,267],[2,268],[2,268],[2,269],[2,269],[2,270],[2,270],[2,271],[2,271],[2,272],[2,272],[2,273],[2,273],[2,274],[2,274],[2,275],[2,275],[2,276],[2,276],[2,277],[2,277],[2,278],[2,278],[2,279],[2,279],[2,280],[2,280],[2,281],[2,281],[2,282],[2,282],[2,283],[2,283],[2,284],[2,284],[2,285],[2,285],[2,286],[2,286],[2,287],[2,287],[2,288],[2,288],[2,289],[2,289],[2,290],[2,290],[2,291],[2,291],[2,292],[2,292],[2,293],[2,293],[2,294],[2,294],[2,295],[2,295],[2,296],[2,296],[2,297],[2,297],[2,298],[2,298],[2,299],[2,299],[2,300],[2,300],[2,301],[2,301],[2,302],[2,302],[2,303],[2,303],[2,304],[2,304],[2,305],[2,305],[2,306],[2,306],[2,307],[2,307],[2,308],[2,308],[2,309],[2,309],[2,310],[2,310],[2,311],[2,311],[2,312],[2,312],[2,313],[2,313],[2,314],[2,314],[2,315],[2,315],[2,316],[2,316],[2,317],[2,317],[2,318],[2,318],[2,319],[2,319],[2,320],[2,320],[2,321],[2,321],[2,322],[2,322],[2,323],[2,323],[2,324],[2,324],[2,325],[2,325],[2,326],[2,326],[2,327],[2,327],[2,328],[2,328],[2,329],[2,329],[2,330],[2,330],[2,331],[2,331],[2,332],[2,332],[2,333],[2,333],[2,334],[2,334],[2,335],[2,335],[2,336],[2,336],[2,337],[2,337],[2,338],[2,338],[2,339],[2,339],[2,340],[2,340],[2,341],[2,341],[2,342],[2,342],[2,343],[2,343],[2,344],[2,344],[2,345],[2,345],[2,346],[2,346],[2,347],[2,347],[2,348],[2,348],[2,349],[2,349],[2,350],[2,350],[2,351],[2,351],[2,352],[2,352],[2,353],[2,353],[2,354],[2,354],[2,355],[2,355],[2,356],[2,356],[2,357],[2,357],[2,358],[2,358],[2,359],[2,359],[2,360],[2,360],[2,361],[2,361],[2,362],[2,362],[2,363],[2,363],[2,364],[2,364],[2,365],[2,365],[2,366],[2,366],[2,367],[2,367],[2,368],[2,368],[2,369],[2,369],[2,370],[2,370],[2,371],[2,371],[2,372],[2,372],[2,373],[2,373],[2,374],[2,374],[2,375],[2,375],[2,376],[2,376],[2,377],[2,377],[2,378],[2,378],[2,379],[2,379],[2,380],[2,380],[2,381],[2,381],[2,382],[2,382],[2,383],[2,383],[2,384],[2,384],[2,385],[2,385],[2,386],[2,386],[2,387],[2,387],[2,388],[2,388],[2,389],[2,389],[2,390],[2,390],[2,391],[2,391],[2,392],[2,392],[2,393],[2,393],[2,394],[2,394],[2,395],[2,395],[2,396],[2,396],[2,397],[2,397],[2,398],[2,398],[2,399],[2,399],[2,400],[2,400],[2,401],[2,401],[2,402],[2,402],[2,403],[2,403],[2,404],[2,404],[2,405],[2,405],[2,406],[2,406],[2,407],[2,407],[2,408],[2,408],[2,409],[2,409],[2,410],[2,410],[2,411],[2,411],[2,412],[2,412],[2,413],[2,413],[2,414],[2,414],[2,415],[2,415],[2,416],[2,416],[2,417],[2,417],[2,418],[2,418],[2,419],[2,419],[2,420],[2,420],[2,421],[2,421],[2,422],[2,422],[2,423],[2,423],[2,424],[2,424],[2,425],[2,425],[2,426],[2,426],[2,427],[2,427],[2,428],[2,428],[2,429],[2,429],[2,430],[2,430],[2,431],[2,431],[2,432],[2,432],[2,433],[2,433],[2,434],[2,434],[2,435],[2,435],[2,436],[2,436],[2,437],[2,437],[2,438],[2,438],[2,439],[2,439],[2,440],[2,440],[2,441],[2,441],[2,442],[2,442],[2,443],[2,443],[2,444],[2,444],[2,445],[2,445],[2,446],[2,446],[2,447],[2,447],[2,448],[2,448],[2,449],[2,449],[2,450],[2,450],[2,451],[2,451],[2,452],[2,452],[2,453],[2,453],[2,454],[2,454],[2,455],[2,455],[2,456],[2,456],[2,457],[2,457],[2,458],[2,458],[2,459],[2,459],[2,460],[2,460],[2,461],[2,461],[2,462],[2,462],[2,463],[2,463],[2,464],[2,464],[2,465],[2,465],[2,466],[2,466],[2,467],[2,467],[2,468],[2,468],[2,469],[2,469],[2,470],[2,470],[2,471],[2,471],[2,472],[2,472],[2,473],[2,473],[2,474],[2,474],[2,475],[2,475],[2,476],[2,476],[2,477],[2,477],[2,478],[2,478],[2,479],[2,479],[2,480],[2,480],[2,481],[2,481],[2,482],[2,482],[2,483],[2,483],[2,484],[2,484],[2,485],[2,485],[2,486],[2,486],[2,487],[2,487],[2,488],[2,488],[2,489],[2,489],[2,490],[2,490],[2,491],[2,491],[2,492],[2,492],[2,493],[2,493],[2,494],[2,494],[2,495],[2,495],[2,496],[2,496],[2,497],[2,497],[2,498],[2,498],[2,499],[2,499],[2,500],[2,500],[3,2],[3,2],[3,3],[3,3],[3,4],[3,4],[3,5],[3,5],[3,6],[3,6],[3,7],[3,7],[3,8],[3,8],[3,9],[3,9],[3,10],[3,10],[3,11],[3,11],[3,12],[3,12],[3,13],[3,13],[3,14],[3,14],[3,15],[3,15],[3,16],[3,16],[3,17],[3,17],[3,18],[3,18],[3,19],[3,19],[3,20],[3,20],[3,21],[3,21],[3,22],[3,22],[3,23],[3,23],[3,24],[3,24],[3,25],[3,25],[3,26],[3,26],[3,27],[3,27],[3,28],[3,28],[3,29],[3,29],[3,30],[3,30],[3,31],[3,31],[3,32],[3,32],[3,33],[3,33],[3,34],[3,34],[3,35],[3,35],[3,36],[3,36],[3,37],[3,37],[3,38],[3,38],[3,39],[3,39],[3,40],[3,40],[3,41],[3,41],[3,42],[3,42],[3,43],[3,43],[3,44],[3,44],[3,45],[3,45],[3,46],[3,46],[3,47],[3,47],[3,48],[3,48],[3,49],[3,49],[3,50],[3,50],[3,51],[3,51],[3,52],[3,52],[3,53],[3,53],[3,54],[3,54],[3,55],[3,55],[3,56],[3,56],[3,57],[3,57],[3,58],[3,58],[3,59],[3,59],[3,60],[3,60],[3,61],[3,61],[3,62],[3,62],[3,63],[3,63],[3,64],[3,64],[3,65],[3,65],[3,66],[3,66],[3,67],[3,67],[3,68],[3,68],[3,69],[3,69],[3,70],[3,70],[3,71],[3,71],[3,72],[3,72],[3,73],[3,73],[3,74],[3,74],[3,75],[3,75],[3,76],[3,76],[3,77],[3,77],[3,78],[3,78],[3,79],[3,79],[3,80],[3,80],[3,81],[3,81],[3,82],[3,82],[3,83],[3,83],[3,84],[3,84],[3,85],[3,85],[3,86],[3,86],[3,87],[3,87],[3,88],[3,88],[3,89],[3,89],[3,90],[3,90],[3,91],[3,91],[3,92],[3,92],[3,93],[3,93],[3,94],[3,94],[3,95],[3,95],[3,96],[3,96],[3,97],[3,97],[3,98],[3,98],[3,99],[3,99],[3,100],[3,100],[3,101],[3,101],[3,102],[3,102],[3,103],[3,103],[3,104],[3,104],[3,105],[3,105],[3,106],[3,106],[3,107],[3,107],[3,108],[3,108],[3,109],[3,109],[3,110],[3,110],[3,111],[3,111],[3,112],[3,112],[3,113],[3,113],[3,114],[3,114],[3,115],[3,115],[3,116],[3,116],[3,117],[3,117],[3,118],[3,118],[3,119],[3,119],[3,120],[3,120],[3,121],[3,121],[3,122],[3,122],[3,123],[3,123],[3,124],[3,124],[3,125],[3,125],[3,126],[3,126],[3,127],[3,127],[3,128],[3,128],[3,129],[3,129],[3,130],[3,130],[3,131],[3,131],[3,132],[3,132],[3,133],[3,133],[3,134],[3,134],[3,135],[3,135],[3,136],[3,136],[3,137],[3,137],[3,138],[3,138],[3,139],[3,139],[3,140],[3,140],[3,141],[3,141],[3,142],[3,142],[3,143],[3,143],[3,144],[3,144],[3,145],[3,145],[3,146],[3,146],[3,147],[3,147],[3,148],[3,148],[3,149],[3,149],[3,150],[3,150],[3,151],[3,151],[3,152],[3,152],[3,153],[3,153],[3,154],[3,154],[3,155],[3,155],[3,156],[3,156],[3,157],[3,157],[3,158],[3,158],[3,159],[3,159],[3,160],[3,160],[3,161],[3,161],[3,162],[3,162],[3,163],[3,163],[3,164],[3,164],[3,165],[3,165],[3,166],[3,166],[3,167],[3,167],[3,168],[3,168],[3,169],[3,169],[3,170],[3,170],[3,171],[3,171],[3,172],[3,172],[3,173],[3,173],[3,174],[3,174],[3,175],[3,175],[3,176],[3,176],[3,177],[3,177],[3,178],[3,178],[3,179],[3,179],[3,180],[3,180],[3,181],[3,181],[3,182],[3,182],[3,183],[3,183],[3,184],[3,184],[3,185],[3,185],[3,186],[3,186],[3,187],[3,187],[3,188],[3,188],[3,189],[3,189],[3,190],[3,190],[3,191],[3,191],[3,192],[3,192],[3,193],[3,193],[3,194],[3,194],[3,195],[3,195],[3,196],[3,196],[3,197],[3,197],[3,198],[3,198],[3,199],[3,199],[3,200],[3,200],[3,201],[3,201],[3,202],[3,202],[3,203],[3,203],[3,204],[3,204],[3,205],[3,205],[3,206],[3,206],[3,207],[3,207],[3,208],[3,208],[3,209],[3,209],[3,210],[3,210],[3,211],[3,211],[3,212],[3,212],[3,213],[3,213],[3,214],[3,214],[3,215],[3,215],[3,216],[3,216],[3,217],[3,217],[3,218],[3,218],[3,219],[3,219],[3,220],[3,220],[3,221],[3,221],[3,222],[3,222],[3,223],[3,223],[3,224],[3,224],[3,225],[3,225],[3,226],[3,226],[3,227],[3,227],[3,228],[3,228],[3,229],[3,229],[3,230],[3,230],[3,231],[3,231],[3,232],[3,232],[3,233],[3,233],[3,234],[3,234],[3,235],[3,235],[3,236],[3,236],[3,237],[3,237],[3,238],[3,238],[3,239],[3,239],[3,240],[3,240],[3,241],[3,241],[3,242],[3,242],[3,243],[3,243],[3,244],[3,244],[3,245],[3,245],[3,246],[3,246],[3,247],[3,247],[3,248],[3,248],[3,249],[3,249],[3,250],[3,250],[3,251],[3,251],[3,252],[3,252],[3,253],[3,253],[3,254],[3,254],[3,255],[3,255],[3,256],[3,256],[3,257],[3,257],[3,258],[3,258],[3,259],[3,259],[3,260],[3,260],[3,261],[3,261],[3,262],[3,262],[3,263],[3,263],[3,264],[3,264],[3,265],[3,265],[3,266],[3,266],[3,267],[3,267],[3,268],[3,268],[3,269],[3,269],[3,270],[3,270],[3,271],[3,271],[3,272],[3,272],[3,273],[3,273],[3,274],[3,274],[3,275],[3,275],[3,276],[3,276],[3,277],[3,277],[3,278],[3,278],[3,279],[3,279],[3,280],[3,280],[3,281],[3,281],[3,282],[3,282],[3,283],[3,283],[3,284],[3,284],[3,285],[3,285],[3,286],[3,286],[3,287],[3,287],[3,288],[3,288],[3,289],[3,289],[3,290],[3,290],[3,291],[3,291],[3,292],[3,292],[3,293],[3,293],[3,294],[3,294],[3,295],[3,295],[3,296],[3,296],[3,297],[3,297],[3,298],[3,298],[3,299],[3,299],[3,300],[3,300],[3,301],[3,301],[3,302],[3,302],[3,303],[3,303],[3,304],[3,304],[3,305],[3,305],[3,306],[3,306],[3,307],[3,307],[3,308],[3,308],[3,309],[3,309],[3,310],[3,310],[3,311],[3,311],[3,312],[3,312],[3,313],[3,313],[3,314],[3,314],[3,315],[3,315],[3,316],[3,316],[3,317],[3,317],[3,318],[3,318],[3,319],[3,319],[3,320],[3,320],[3,321],[3,321],[3,322],[3,322],[3,323],[3,323],[3,324],[3,324],[3,325],[3,325],[3,326],[3,326],[3,327],[3,327],[3,328],[3,328],[3,329],[3,329],[3,330],[3,330],[3,331],[3,331],[3,332],[3,332],[3,333],[3,333],[3,334],[3,334],[3,335],[3,335],[3,336],[3,336],[3,337],[3,337],[3,338],[3,338],[3,339],[3,339],[3,340],[3,340],[3,341],[3,341],[3,342],[3,342],[3,343],[3,343],[3,344],[3,344],[3,345],[3,345],[3,346],[3,346],[3,347],[3,347],[3,348],[3,348],[3,349],[3,349],[3,350],[3,350],[3,351],[3,351],[3,352],[3,352],[3,353],[3,353],[3,354],[3,354],[3,355],[3,355],[3,356],[3,356],[3,357],[3,357],[3,358],[3,358],[3,359],[3,359],[3,360],[3,360],[3,361],[3,361],[3,362],[3,362],[3,363],[3,363],[3,364],[3,364],[3,365],[3,365],[3,366],[3,366],[3,367],[3,367],[3,368],[3,368],[3,369],[3,369],[3,370],[3,370],[3,371],[3,371],[3,372],[3,372],[3,373],[3,373],[3,374],[3,374],[3,375],[3,375],[3,376],[3,376],[3,377],[3,377],[3,378],[3,378],[3,379],[3,379],[3,380],[3,380],[3,381],[3,381],[3,382],[3,382],[3,383],[3,383],[3,384],[3,384],[3,385],[3,385],[3,386],[3,386],[3,387],[3,387],[3,388],[3,388],[3,389],[3,389],[3,390],[3,390],[3,391],[3,391],[3,392],[3,392],[3,393],[3,393],[3,394],[3,394],[3,395],[3,395],[3,396],[3,396],[3,397],[3,397],[3,398],[3,398],[3,399],[3,399],[3,400],[3,400],[3,401],[3,401],[3,402],[3,402],[3,403],[3,403],[3,404],[3,404],[3,405],[3,405],[3,406],[3,406],[3,407],[3,407],[3,408],[3,408],[3,409],[3,409],[3,410],[3,410],[3,411],[3,411],[3,412],[3,412],[3,413],[3,413],[3,414],[3,414],[3,415],[3,415],[3,416],[3,416],[3,417],[3,417],[3,418],[3,418],[3,419],[3,419],[3,420],[3,420],[3,421],[3,421],[3,422],[3,422],[3,423],[3,423],[3,424],[3,424],[3,425],[3,425],[3,426],[3,426],[3,427],[3,427],[3,428],[3,428],[3,429],[3,429],[3,430],[3,430],[3,431],[3,431],[3,432],[3,432],[3,433],[3,433],[3,434],[3,434],[3,435],[3,435],[3,436],[3,436],[3,437],[3,437],[3,438],[3,438],[3,439],[3,439],[3,440],[3,440],[3,441],[3,441],[3,442],[3,442],[3,443],[3,443],[3,444],[3,444],[3,445],[3,445],[3,446],[3,446],[3,447],[3,447],[3,448],[3,448],[3,449],[3,449],[3,450],[3,450],[3,451],[3,451],[3,452],[3,452],[3,453],[3,453],[3,454],[3,454],[3,455],[3,455],[3,456],[3,456],[3,457],[3,457],[3,458],[3,458],[3,459],[3,459],[3,460],[3,460],[3,461],[3,461],[3,462],[3,462],[3,463],[3,463],[3,464],[3,464],[3,465],[3,465],[3,466],[3,466],[3,467],[3,467],[3,468],[3,468],[3,469],[3,469],[3,470],[3,470],[3,471],[3,471],[3,472],[3,472],[3,473],[3,473],[3,474],[3,474],[3,475],[3,475],[3,476],[3,476],[3,477],[3,477],[3,478],[3,478],[3,479],[3,479],[3,480],[3,480],[3,481],[3,481],[3,482],[3,482],[3,483],[3,483],[3,484],[3,484],[3,485],[3,485],[3,486],[3,486],[3,487],[3,487],[3,488],[3,488],[3,489],[3,489],[3,490],[3,490],[3,491],[3,491],[3,492],[3,492],[3,493],[3,493],[3,494],[3,494],[3,495],[3,495],[3,496],[3,496],[3,497],[3,497],[3,498],[3,498],[3,499],[3,499],[3,500],[3,500],[4,2],[4,2],[4,3],[4,3],[4,4],[4,4],[4,5],[4,5],[4,6],[4,6],[4,7],[4,7],[4,8],[4,8],[4,9],[4,9],[4,10],[4,10],[4,11],[4,11],[4,12],[4,12],[4,13],[4,13],[4,14],[4,14],[4,15],[4,15],[4,16],[4,16],[4,17],[4,17],[4,18],[4,18],[4,19],[4,19],[4,20],[4,20],[4,21],[4,21],[4,22],[4,22],[4,23],[4,23],[4,24],[4,24],[4,25],[4,25],[4,26],[4,26],[4,27],[4,27],[4,28],[4,28],[4,29],[4,29],[4,30],[4,30],[4,31],[4,31],[4,32],[4,32],[4,33],[4,33],[4,34],[4,34],[4,35],[4,35],[4,36],[4,36],[4,37],[4,37],[4,38],[4,38],[4,39],[4,39],[4,40],[4,40],[4,41],[4,41],[4,42],[4,42],[4,43],[4,43],[4,44],[4,44],[4,45],[4,45],[4,46],[4,46],[4,47],[4,47],[4,48],[4,48],[4,49],[4,49],[4,50],[4,50],[4,51],[4,51],[4,52],[4,52],[4,53],[4,53],[4,54],[4,54],[4,55],[4,55],[4,56],[4,56],[4,57],[4,57],[4,58],[4,58],[4,59],[4,59],[4,60],[4,60],[4,61],[4,61],[4,62],[4,62],[4,63],[4,63],[4,64],[4,64],[4,65],[4,65],[4,66],[4,66],[4,67],[4,67],[4,68],[4,68],[4,69],[4,69],[4,70],[4,70],[4,71],[4,71],[4,72],[4,72],[4,73],[4,73],[4,74],[4,74],[4,75],[4,75],[4,76],[4,76],[4,77],[4,77],[4,78],[4,78],[4,79],[4,79],[4,80],[4,80],[4,81],[4,81],[4,82],[4,82],[4,83],[4,83],[4,84],[4,84],[4,85],[4,85],[4,86],[4,86],[4,87],[4,87],[4,88],[4,88],[4,89],[4,89],[4,90],[4,90],[4,91],[4,91],[4,92],[4,92],[4,93],[4,93],[4,94],[4,94],[4,95],[4,95],[4,96],[4,96],[4,97],[4,97],[4,98],[4,98],[4,99],[4,99],[4,100],[4,100],[4,101],[4,101],[4,102],[4,102],[4,103],[4,103],[4,104],[4,104],[4,105],[4,105],[4,106],[4,106],[4,107],[4,107],[4,108],[4,108],[4,109],[4,109],[4,110],[4,110],[4,111],[4,111],[4,112],[4,112],[4,113],[4,113],[4,114],[4,114],[4,115],[4,115],[4,116],[4,116],[4,117],[4,117],[4,118],[4,118],[4,119],[4,119],[4,120],[4,120],[4,121],[4,121],[4,122],[4,122],[4,123],[4,123],[4,124],[4,124],[4,125],[4,125],[4,126],[4,126],[4,127],[4,127],[4,128],[4,128],[4,129],[4,129],[4,130],[4,130],[4,131],[4,131],[4,132],[4,132],[4,133],[4,133],[4,134],[4,134],[4,135],[4,135],[4,136],[4,136],[4,137],[4,137],[4,138],[4,138],[4,139],[4,139],[4,140],[4,140],[4,141],[4,141],[4,142],[4,142],[4,143],[4,143],[4,144],[4,144],[4,145],[4,145],[4,146],[4,146],[4,147],[4,147],[4,148],[4,148],[4,149],[4,149],[4,150],[4,150],[4,151],[4,151],[4,152],[4,152],[4,153],[4,153],[4,154],[4,154],[4,155],[4,155],[4,156],[4,156],[4,157],[4,157],[4,158],[4,158],[4,159],[4,159],[4,160],[4,160],[4,161],[4,161],[4,162],[4,162],[4,163],[4,163],[4,164],[4,164],[4,165],[4,165],[4,166],[4,166],[4,167],[4,167],[4,168],[4,168],[4,169],[4,169],[4,170],[4,170],[4,171],[4,171],[4,172],[4,172],[4,173],[4,173],[4,174],[4,174],[4,175],[4,175],[4,176],[4,176],[4,177],[4,177],[4,178],[4,178],[4,179],[4,179],[4,180],[4,180],[4,181],[4,181],[4,182],[4,182],[4,183],[4,183],[4,184],[4,184],[4,185],[4,185],[4,186],[4,186],[4,187],[4,187],[4,188],[4,188],[4,189],[4,189],[4,190],[4,190],[4,191],[4,191],[4,192],[4,192],[4,193],[4,193],[4,194],[4,194],[4,195],[4,195],[4,196],[4,196],[4,197],[4,197],[4,198],[4,198],[4,199],[4,199],[4,200],[4,200],[4,201],[4,201],[4,202],[4,202],[4,203],[4,203],[4,204],[4,204],[4,205],[4,205],[4,206],[4,206],[4,207],[4,207],[4,208],[4,208],[4,209],[4,209],[4,210],[4,210],[4,211],[4,211],[4,212],[4,212],[4,213],[4,213],[4,214],[4,214],[4,215],[4,215],[4,216],[4,216],[4,217],[4,217],[4,218],[4,218],[4,219],[4,219],[4,220],[4,220],[4,221],[4,221],[4,222],[4,222],[4,223],[4,223],[4,224],[4,224],[4,225],[4,225],[4,226],[4,226],[4,227],[4,227],[4,228],[4,228],[4,229],[4,229],[4,230],[4,230],[4,231],[4,231],[4,232],[4,232],[4,233],[4,233],[4,234],[4,234],[4,235],[4,235],[4,236],[4,236],[4,237],[4,237],[4,238],[4,238],[4,239],[4,239],[4,240],[4,240],[4,241],[4,241],[4,242],[4,242],[4,243],[4,243],[4,244],[4,244],[4,245],[4,245],[4,246],[4,246],[4,247],[4,247],[4,248],[4,248],[4,249],[4,249],[4,250],[4,250],[4,251],[4,251],[4,252],[4,252],[4,253],[4,253],[4,254],[4,254],[4,255],[4,255],[4,256],[4,256],[4,257],[4,257],[4,258],[4,258],[4,259],[4,259],[4,260],[4,260],[4,261],[4,261],[4,262],[4,262],[4,263],[4,263],[4,264],[4,264],[4,265],[4,265],[4,266],[4,266],[4,267],[4,267],[4,268],[4,268],[4,269],[4,269],[4,270],[4,270],[4,271],[4,271],[4,272],[4,272],[4,273],[4,273],[4,274],[4,274],[4,275],[4,275],[4,276],[4,276],[4,277],[4,277],[4,278],[4,278],[4,279],[4,279],[4,280],[4,280],[4,281],[4,281],[4,282],[4,282],[4,283],[4,283],[4,284],[4,284],[4,285],[4,285],[4,286],[4,286],[4,287],[4,287],[4,288],[4,288],[4,289],[4,289],[4,290],[4,290],[4,291],[4,291],[4,292],[4,292],[4,293],[4,293],[4,294],[4,294],[4,295],[4,295],[4,296],[4,296],[4,297],[4,297],[4,298],[4,298],[4,299],[4,299],[4,300],[4,300],[4,301],[4,301],[4,302],[4,302],[4,303],[4,303],[4,304],[4,304],[4,305],[4,305],[4,306],[4,306],[4,307],[4,307],[4,308],[4,308],[4,309],[4,309],[4,310],[4,310],[4,311],[4,311],[4,312],[4,312],[4,313],[4,313],[4,314],[4,314],[4,315],[4,315],[4,316],[4,316],[4,317],[4,317],[4,318],[4,318],[4,319],[4,319],[4,320],[4,320],[4,321],[4,321],[4,322],[4,322],[4,323],[4,323],[4,324],[4,324],[4,325],[4,325],[4,326],[4,326],[4,327],[4,327],[4,328],[4,328],[4,329],[4,329],[4,330],[4,330],[4,331],[4,331],[4,332],[4,332],[4,333],[4,333],[4,334],[4,334],[4,335],[4,335],[4,336],[4,336],[4,337],[4,337],[4,338],[4,338],[4,339],[4,339],[4,340],[4,340],[4,341],[4,341],[4,342],[4,342],[4,343],[4,343],[4,344],[4,344],[4,345],[4,345],[4,346],[4,346],[4,347],[4,347],[4,348],[4,348],[4,349],[4,349],[4,350],[4,350],[4,351],[4,351],[4,352],[4,352],[4,353],[4,353],[4,354],[4,354],[4,355],[4,355],[4,356],[4,356],[4,357],[4,357],[4,358],[4,358],[4,359],[4,359],[4,360],[4,360],[4,361],[4,361],[4,362],[4,362],[4,363],[4,363],[4,364],[4,364],[4,365],[4,365],[4,366],[4,366],[4,367],[4,367],[4,368],[4,368],[4,369],[4,369],[4,370],[4,370],[4,371],[4,371],[4,372],[4,372],[4,373],[4,373],[4,374],[4,374],[4,375],[4,375],[4,376],[4,376],[4,377],[4,377],[4,378],[4,378],[4,379],[4,379],[4,380],[4,380],[4,381],[4,381],[4,382],[4,382],[4,383],[4,383],[4,384],[4,384],[4,385],[4,385],[4,386],[4,386],[4,387],[4,387],[4,388],[4,388],[4,389],[4,389],[4,390],[4,390],[4,391],[4,391],[4,392],[4,392],[4,393],[4,393],[4,394],[4,394],[4,395],[4,395],[4,396],[4,396],[4,397],[4,397],[4,398],[4,398],[4,399],[4,399],[4,400],[4,400],[4,401],[4,401],[4,402],[4,402],[4,403],[4,403],[4,404],[4,404],[4,405],[4,405],[4,406],[4,406],[4,407],[4,407],[4,408],[4,408],[4,409],[4,409],[4,410],[4,410],[4,411],[4,411],[4,412],[4,412],[4,413],[4,413],[4,414],[4,414],[4,415],[4,415],[4,416],[4,416],[4,417],[4,417],[4,418],[4,418],[4,419],[4,419],[4,420],[4,420],[4,421],[4,421],[4,422],[4,422],[4,423],[4,423],[4,424],[4,424],[4,425],[4,425],[4,426],[4,426],[4,427],[4,427],[4,428],[4,428],[4,429],[4,429],[4,430],[4,430],[4,431],[4,431],[4,432],[4,432],[4,433],[4,433],[4,434],[4,434],[4,435],[4,435],[4,436],[4,436],[4,437],[4,437],[4,438],[4,438],[4,439],[4,439],[4,440],[4,440],[4,441],[4,441],[4,442],[4,442],[4,443],[4,443],[4,444],[4,444],[4,445],[4,445],[4,446],[4,446],[4,447],[4,447],[4,448],[4,448],[4,449],[4,449],[4,450],[4,450],[4,451],[4,451],[4,452],[4,452],[4,453],[4,453],[4,454],[4,454],[4,455],[4,455],[4,456],[4,456],[4,457],[4,457],[4,458],[4,458],[4,459],[4,459],[4,460],[4,460],[4,461],[4,461],[4,462],[4,462],[4,463],[4,463],[4,464],[4,464],[4,465],[4,465],[4,466],[4,466],[4,467],[4,467],[4,468],[4,468],[4,469],[4,469],[4,470],[4,470],[4,471],[4,471],[4,472],[4,472],[4,473],[4,473],[4,474],[4,474],[4,475],[4,475],[4,476],[4,476],[4,477],[4,477],[4,478],[4,478],[4,479],[4,479],[4,480],[4,480],[4,481],[4,481],[4,482],[4,482],[4,483],[4,483],[4,484],[4,484],[4,485],[4,485],[4,486],[4,486],[4,487],[4,487],[4,488],[4,488],[4,489],[4,489],[4,490],[4,490],[4,491],[4,491],[4,492],[4,492],[4,493],[4,493],[4,494],[4,494],[4,495],[4,495],[4,496],[4,496],[4,497],[4,497],[4,498],[4,498],[4,499],[4,499],[4,500],[4,500],[5,2],[5,2],[5,3],[5,3],[5,4],[5,4],[5,5],[5,5],[5,6],[5,6],[5,7],[5,7],[5,8],[5,8],[5,9],[5,9],[5,10],[5,10],[5,11],[5,11],[5,12],[5,12],[5,13],[5,13],[5,14],[5,14],[5,15],[5,15],[5,16],[5,16],[5,17],[5,17],[5,18],[5,18],[5,19],[5,19],[5,20],[5,20],[5,21],[5,21],[5,22],[5,22],[5,23],[5,23],[5,24],[5,24],[5,25],[5,25],[5,26],[5,26],[5,27],[5,27],[5,28],[5,28],[5,29],[5,29],[5,30],[5,30],[5,31],[5,31],[5,32],[5,32],[5,33],[5,33],[5,34],[5,34],[5,35],[5,35],[5,36],[5,36],[5,37],[5,37],[5,38],[5,38],[5,39],[5,39],[5,40],[5,40],[5,41],[5,41],[5,42],[5,42],[5,43],[5,43],[5,44],[5,44],[5,45],[5,45],[5,46],[5,46],[5,47],[5,47],[5,48],[5,48],[5,49],[5,49],[5,50],[5,50],[5,51],[5,51],[5,52],[5,52],[5,53],[5,53],[5,54],[5,54],[5,55],[5,55],[5,56],[5,56],[5,57],[5,57],[5,58],[5,58],[5,59],[5,59],[5,60],[5,60],[5,61],[5,61],[5,62],[5,62],[5,63],[5,63],[5,64],[5,64],[5,65],[5,65],[5,66],[5,66],[5,67],[5,67],[5,68],[5,68],[5,69],[5,69],[5,70],[5,70],[5,71],[5,71],[5,72],[5,72],[5,73],[5,73],[5,74],[5,74],[5,75],[5,75],[5,76],[5,76],[5,77],[5,77],[5,78],[5,78],[5,79],[5,79],[5,80],[5,80],[5,81],[5,81],[5,82],[5,82],[5,83],[5,83],[5,84],[5,84],[5,85],[5,85],[5,86],[5,86],[5,87],[5,87],[5,88],[5,88],[5,89],[5,89],[5,90],[5,90],[5,91],[5,91],[5,92],[5,92],[5,93],[5,93],[5,94],[5,94],[5,95],[5,95],[5,96],[5,96],[5,97],[5,97],[5,98],[5,98],[5,99],[5,99],[5,100],[5,100],[5,101],[5,101],[5,102],[5,102],[5,103],[5,103],[5,104],[5,104],[5,105],[5,105],[5,106],[5,106],[5,107],[5,107],[5,108],[5,108],[5,109],[5,109],[5,110],[5,110],[5,111],[5,111],[5,112],[5,112],[5,113],[5,113],[5,114],[5,114],[5,115],[5,115],[5,116],[5,116],[5,117],[5,117],[5,118],[5,118],[5,119],[5,119],[5,120],[5,120],[5,121],[5,121],[5,122],[5,122],[5,123],[5,123],[5,124],[5,124],[5,125],[5,125],[5,126],[5,126],[5,127],[5,127],[5,128],[5,128],[5,129],[5,129],[5,130],[5,130],[5,131],[5,131],[5,132],[5,132],[5,133],[5,133],[5,134],[5,134],[5,135],[5,135],[5,136],[5,136],[5,137],[5,137],[5,138],[5,138],[5,139],[5,139],[5,140],[5,140],[5,141],[5,141],[5,142],[5,142],[5,143],[5,143],[5,144],[5,144],[5,145],[5,145],[5,146],[5,146],[5,147],[5,147],[5,148],[5,148],[5,149],[5,149],[5,150],[5,150],[5,151],[5,151],[5,152],[5,152],[5,153],[5,153],[5,154],[5,154],[5,155],[5,155],[5,156],[5,156],[5,157],[5,157],[5,158],[5,158],[5,159],[5,159],[5,160],[5,160],[5,161],[5,161],[5,162],[5,162],[5,163],[5,163],[5,164],[5,164],[5,165],[5,165],[5,166],[5,166],[5,167],[5,167],[5,168],[5,168],[5,169],[5,169],[5,170],[5,170],[5,171],[5,171],[5,172],[5,172],[5,173],[5,173],[5,174],[5,174],[5,175],[5,175],[5,176],[5,176],[5,177],[5,177],[5,178],[5,178],[5,179],[5,179],[5,180],[5,180],[5,181],[5,181],[5,182],[5,182],[5,183],[5,183],[5,184],[5,184],[5,185],[5,185],[5,186],[5,186],[5,187],[5,187],[5,188],[5,188],[5,189],[5,189],[5,190],[5,190],[5,191],[5,191],[5,192],[5,192],[5,193],[5,193],[5,194],[5,194],[5,195],[5,195],[5,196],[5,196],[5,197],[5,197],[5,198],[5,198],[5,199],[5,199],[5,200],[5,200],[5,201],[5,201],[5,202],[5,202],[5,203],[5,203],[5,204],[5,204],[5,205],[5,205],[5,206],[5,206],[5,207],[5,207],[5,208],[5,208],[5,209],[5,209],[5,210],[5,210],[5,211],[5,211],[5,212],[5,212],[5,213],[5,213],[5,214],[5,214],[5,215],[5,215],[5,216],[5,216],[5,217],[5,217],[5,218],[5,218],[5,219],[5,219],[5,220],[5,220],[5,221],[5,221],[5,222],[5,222],[5,223],[5,223],[5,224],[5,224],[5,225],[5,225],[5,226],[5,226],[5,227],[5,227],[5,228],[5,228],[5,229],[5,229],[5,230],[5,230],[5,231],[5,231],[5,232],[5,232],[5,233],[5,233],[5,234],[5,234],[5,235],[5,235],[5,236],[5,236],[5,237],[5,237],[5,238],[5,238],[5,239],[5,239],[5,240],[5,240],[5,241],[5,241],[5,242],[5,242],[5,243],[5,243],[5,244],[5,244],[5,245],[5,245],[5,246],[5,246],[5,247],[5,247],[5,248],[5,248],[5,249],[5,249],[5,250],[5,250],[5,251],[5,251],[5,252],[5,252],[5,253],[5,253],[5,254],[5,254],[5,255],[5,255],[5,256],[5,256],[5,257],[5,257],[5,258],[5,258],[5,259],[5,259],[5,260],[5,260],[5,261],[5,261],[5,262],[5,262],[5,263],[5,263],[5,264],[5,264],[5,265],[5,265],[5,266],[5,266],[5,267],[5,267],[5,268],[5,268],[5,269],[5,269],[5,270],[5,270],[5,271],[5,271],[5,272],[5,272],[5,273],[5,273],[5,274],[5,274],[5,275],[5,275],[5,276],[5,276],[5,277],[5,277],[5,278],[5,278],[5,279],[5,279],[5,280],[5,280],[5,281],[5,281],[5,282],[5,282],[5,283],[5,283],[5,284],[5,284],[5,285],[5,285],[5,286],[5,286],[5,287],[5,287],[5,288],[5,288],[5,289],[5,289],[5,290],[5,290],[5,291],[5,291],[5,292],[5,292],[5,293],[5,293],[5,294],[5,294],[5,295],[5,295],[5,296],[5,296],[5,297],[5,297],[5,298],[5,298],[5,299],[5,299],[5,300],[5,300],[5,301],[5,301],[5,302],[5,302],[5,303],[5,303],[5,304],[5,304],[5,305],[5,305],[5,306],[5,306],[5,307],[5,307],[5,308],[5,308],[5,309],[5,309],[5,310],[5,310],[5,311],[5,311],[5,312],[5,312],[5,313],[5,313],[5,314],[5,314],[5,315],[5,315],[5,316],[5,316],[5,317],[5,317],[5,318],[5,318],[5,319],[5,319],[5,320],[5,320],[5,321],[5,321],[5,322],[5,322],[5,323],[5,323],[5,324],[5,324],[5,325],[5,325],[5,326],[5,326],[5,327],[5,327],[5,328],[5,328],[5,329],[5,329],[5,330],[5,330],[5,331],[5,331],[5,332],[5,332],[5,333],[5,333],[5,334],[5,334],[5,335],[5,335],[5,336],[5,336],[5,337],[5,337],[5,338],[5,338],[5,339],[5,339],[5,340],[5,340],[5,341],[5,341],[5,342],[5,342],[5,343],[5,343],[5,344],[5,344],[5,345],[5,345],[5,346],[5,346],[5,347],[5,347],[5,348],[5,348],[5,349],[5,349],[5,350],[5,350],[5,351],[5,351],[5,352],[5,352],[5,353],[5,353],[5,354],[5,354],[5,355],[5,355],[5,356],[5,356],[5,357],[5,357],[5,358],[5,358],[5,359],[5,359],[5,360],[5,360],[5,361],[5,361],[5,362],[5,362],[5,363],[5,363],[5,364],[5,364],[5,365],[5,365],[5,366],[5,366],[5,367],[5,367],[5,368],[5,368],[5,369],[5,369],[5,370],[5,370],[5,371],[5,371],[5,372],[5,372],[5,373],[5,373],[5,374],[5,374],[5,375],[5,375],[5,376],[5,376],[5,377],[5,377],[5,378],[5,378],[5,379],[5,379],[5,380],[5,380],[5,381],[5,381],[5,382],[5,382],[5,383],[5,383],[5,384],[5,384],[5,385],[5,385],[5,386],[5,386],[5,387],[5,387],[5,388],[5,388],[5,389],[5,389],[5,390],[5,390],[5,391],[5,391],[5,392],[5,392],[5,393],[5,393],[5,394],[5,394],[5,395],[5,395],[5,396],[5,396],[5,397],[5,397],[5,398],[5,398],[5,399],[5,399],[5,400],[5,400],[5,401],[5,401],[5,402],[5,402],[5,403],[5,403],[5,404],[5,404],[5,405],[5,405],[5,406],[5,406],[5,407],[5,407],[5,408],[5,408],[5,409],[5,409],[5,410],[5,410],[5,411],[5,411],[5,412],[5,412],[5,413],[5,413],[5,414],[5,414],[5,415],[5,415],[5,416],[5,416],[5,417],[5,417],[5,418],[5,418],[5,419],[5,419],[5,420],[5,420],[5,421],[5,421],[5,422],[5,422],[5,423],[5,423],[5,424],[5,424],[5,425],[5,425],[5,426],[5,426],[5,427],[5,427],[5,428],[5,428],[5,429],[5,429],[5,430],[5,430],[5,431],[5,431],[5,432],[5,432],[5,433],[5,433],[5,434],[5,434],[5,435],[5,435],[5,436],[5,436],[5,437],[5,437],[5,438],[5,438],[5,439],[5,439],[5,440],[5,440],[5,441],[5,441],[5,442],[5,442],[5,443],[5,443],[5,444],[5,444],[5,445],[5,445],[5,446],[5,446],[5,447],[5,447],[5,448],[5,448],[5,449],[5,449],[5,450],[5,450],[5,451],[5,451],[5,452],[5,452],[5,453],[5,453],[5,454],[5,454],[5,455],[5,455],[5,456],[5,456],[5,457],[5,457],[5,458],[5,458],[5,459],[5,459],[5,460],[5,460],[5,461],[5,461],[5,462],[5,462],[5,463],[5,463],[5,464],[5,464],[5,465],[5,465],[5,466],[5,466],[5,467],[5,467],[5,468],[5,468],[5,469],[5,469],[5,470],[5,470],[5,471],[5,471],[5,472],[5,472],[5,473],[5,473],[5,474],[5,474],[5,475],[5,475],[5,476],[5,476],[5,477],[5,477],[5,478],[5,478],[5,479],[5,479],[5,480],[5,480],[5,481],[5,481],[5,482],[5,482],[5,483],[5,483],[5,484],[5,484],[5,485],[5,485],[5,486],[5,486],[5,487],[5,487],[5,488],[5,488],[5,489],[5,489],[5,490],[5,490],[5,491],[5,491],[5,492],[5,492],[5,493],[5,493],[5,494],[5,494],[5,495],[5,495],[5,496],[5,496],[5,497],[5,497],[5,498],[5,498],[5,499],[5,499],[5,500],[5,500],[6,2],[6,2],[6,3],[6,3],[6,4],[6,4],[6,5],[6,5],[6,6],[6,6],[6,7],[6,7],[6,8],[6,8],[6,9],[6,9],[6,10],[6,10],[6,11],[6,11],[6,12],[6,12],[6,13],[6,13],[6,14],[6,14],[6,15],[6,15],[6,16],[6,16],[6,17],[6,17],[6,18],[6,18],[6,19],[6,19],[6,20],[6,20],[6,21],[6,21],[6,22],[6,22],[6,23],[6,23],[6,24],[6,24],[6,25],[6,25],[6,26],[6,26],[6,27],[6,27],[6,28],[6,28],[6,29],[6,29],[6,30],[6,30],[6,31],[6,31],[6,32],[6,32],[6,33],[6,33],[6,34],[6,34],[6,35],[6,35],[6,36],[6,36],[6,37],[6,37],[6,38],[6,38],[6,39],[6,39],[6,40],[6,40],[6,41],[6,41],[6,42],[6,42],[6,43],[6,43],[6,44],[6,44],[6,45],[6,45],[6,46],[6,46],[6,47],[6,47],[6,48],[6,48],[6,49],[6,49],[6,50],[6,50],[6,51],[6,51],[6,52],[6,52],[6,53],[6,53],[6,54],[6,54],[6,55],[6,55],[6,56],[6,56],[6,57],[6,57],[6,58],[6,58],[6,59],[6,59],[6,60],[6,60],[6,61],[6,61],[6,62],[6,62],[6,63],[6,63],[6,64],[6,64],[6,65],[6,65],[6,66],[6,66],[6,67],[6,67],[6,68],[6,68],[6,69],[6,69],[6,70],[6,70],[6,71],[6,71],[6,72],[6,72],[6,73],[6,73],[6,74],[6,74],[6,75],[6,75],[6,76],[6,76],[6,77],[6,77],[6,78],[6,78],[6,79],[6,79],[6,80],[6,80],[6,81],[6,81],[6,82],[6,82],[6,83],[6,83],[6,84],[6,84],[6,85],[6,85],[6,86],[6,86],[6,87],[6,87],[6,88],[6,88],[6,89],[6,89],[6,90],[6,90],[6,91],[6,91],[6,92],[6,92],[6,93],[6,93],[6,94],[6,94],[6,95],[6,95],[6,96],[6,96],[6,97],[6,97],[6,98],[6,98],[6,99],[6,99],[6,100],[6,100],[6,101],[6,101],[6,102],[6,102],[6,103],[6,103],[6,104],[6,104],[6,105],[6,105],[6,106],[6,106],[6,107],[6,107],[6,108],[6,108],[6,109],[6,109],[6,110],[6,110],[6,111],[6,111],[6,112],[6,112],[6,113],[6,113],[6,114],[6,114],[6,115],[6,115],[6,116],[6,116],[6,117],[6,117],[6,118],[6,118],[6,119],[6,119],[6,120],[6,120],[6,121],[6,121],[6,122],[6,122],[6,123],[6,123],[6,124],[6,124],[6,125],[6,125],[6,126],[6,126],[6,127],[6,127],[6,128],[6,128],[6,129],[6,129],[6,130],[6,130],[6,131],[6,131],[6,132],[6,132],[6,133],[6,133],[6,134],[6,134],[6,135],[6,135],[6,136],[6,136],[6,137],[6,137],[6,138],[6,138],[6,139],[6,139],[6,140],[6,140],[6,141],[6,141],[6,142],[6,142],[6,143],[6,143],[6,144],[6,144],[6,145],[6,145],[6,146],[6,146],[6,147],[6,147],[6,148],[6,148],[6,149],[6,149],[6,150],[6,150],[6,151],[6,151],[6,152],[6,152],[6,153],[6,153],[6,154],[6,154],[6,155],[6,155],[6,156],[6,156],[6,157],[6,157],[6,158],[6,158],[6,159],[6,159],[6,160],[6,160],[6,161],[6,161],[6,162],[6,162],[6,163],[6,163],[6,164],[6,164],[6,165],[6,165],[6,166],[6,166],[6,167],[6,167],[6,168],[6,168],[6,169],[6,169],[6,170],[6,170],[6,171],[6,171],[6,172],[6,172],[6,173],[6,173],[6,174],[6,174],[6,175],[6,175],[6,176],[6,176],[6,177],[6,177],[6,178],[6,178],[6,179],[6,179],[6,180],[6,180],[6,181],[6,181],[6,182],[6,182],[6,183],[6,183],[6,184],[6,184],[6,185],[6,185],[6,186],[6,186],[6,187],[6,187],[6,188],[6,188],[6,189],[6,189],[6,190],[6,190],[6,191],[6,191],[6,192],[6,192],[6,193],[6,193],[6,194],[6,194],[6,195],[6,195],[6,196],[6,196],[6,197],[6,197],[6,198],[6,198],[6,199],[6,199],[6,200],[6,200],[6,201],[6,201],[6,202],[6,202],[6,203],[6,203],[6,204],[6,204],[6,205],[6,205],[6,206],[6,206],[6,207],[6,207],[6,208],[6,208],[6,209],[6,209],[6,210],[6,210],[6,211],[6,211],[6,212],[6,212],[6,213],[6,213],[6,214],[6,214],[6,215],[6,215],[6,216],[6,216],[6,217],[6,217],[6,218],[6,218],[6,219],[6,219],[6,220],[6,220],[6,221],[6,221],[6,222],[6,222],[6,223],[6,223],[6,224],[6,224],[6,225],[6,225],[6,226],[6,226],[6,227],[6,227],[6,228],[6,228],[6,229],[6,229],[6,230],[6,230],[6,231],[6,231],[6,232],[6,232],[6,233],[6,233],[6,234],[6,234],[6,235],[6,235],[6,236],[6,236],[6,237],[6,237],[6,238],[6,238],[6,239],[6,239],[6,240],[6,240],[6,241],[6,241],[6,242],[6,242],[6,243],[6,243],[6,244],[6,244],[6,245],[6,245],[6,246],[6,246],[6,247],[6,247],[6,248],[6,248],[6,249],[6,249],[6,250],[6,250],[6,251],[6,251],[6,252],[6,252],[6,253],[6,253],[6,254],[6,254],[6,255],[6,255],[6,256],[6,256],[6,257],[6,257],[6,258],[6,258],[6,259],[6,259],[6,260],[6,260],[6,261],[6,261],[6,262],[6,262],[6,263],[6,263],[6,264],[6,264],[6,265],[6,265],[6,266],[6,266],[6,267],[6,267],[6,268],[6,268],[6,269],[6,269],[6,270],[6,270],[6,271],[6,271],[6,272],[6,272],[6,273],[6,273],[6,274],[6,274],[6,275],[6,275],[6,276],[6,276],[6,277],[6,277],[6,278],[6,278],[6,279],[6,279],[6,280],[6,280],[6,281],[6,281],[6,282],[6,282],[6,283],[6,283],[6,284],[6,284],[6,285],[6,285],[6,286],[6,286],[6,287],[6,287],[6,288],[6,288],[6,289],[6,289],[6,290],[6,290],[6,291],[6,291],[6,292],[6,292],[6,293],[6,293],[6,294],[6,294],[6,295],[6,295],[6,296],[6,296],[6,297],[6,297],[6,298],[6,298],[6,299],[6,299],[6,300],[6,300],[6,301],[6,301],[6,302],[6,302],[6,303],[6,303],[6,304],[6,304],[6,305],[6,305],[6,306],[6,306],[6,307],[6,307],[6,308],[6,308],[6,309],[6,309],[6,310],[6,310],[6,311],[6,311],[6,312],[6,312],[6,313],[6,313],[6,314],[6,314],[6,315],[6,315],[6,316],[6,316],[6,317],[6,317],[6,318],[6,318],[6,319],[6,319],[6,320],[6,320],[6,321],[6,321],[6,322],[6,322],[6,323],[6,323],[6,324],[6,324],[6,325],[6,325],[6,326],[6,326],[6,327],[6,327],[6,328],[6,328],[6,329],[6,329],[6,330],[6,330],[6,331],[6,331],[6,332],[6,332],[6,333],[6,333],[6,334],[6,334],[6,335],[6,335],[6,336],[6,336],[6,337],[6,337],[6,338],[6,338],[6,339],[6,339],[6,340],[6,340],[6,341],[6,341],[6,342],[6,342],[6,343],[6,343],[6,344],[6,344],[6,345],[6,345],[6,346],[6,346],[6,347],[6,347],[6,348],[6,348],[6,349],[6,349],[6,350],[6,350],[6,351],[6,351],[6,352],[6,352],[6,353],[6,353],[6,354],[6,354],[6,355],[6,355],[6,356],[6,356],[6,357],[6,357],[6,358],[6,358],[6,359],[6,359],[6,360],[6,360],[6,361],[6,361],[6,362],[6,362],[6,363],[6,363],[6,364],[6,364],[6,365],[6,365],[6,366],[6,366],[6,367],[6,367],[6,368],[6,368],[6,369],[6,369],[6,370],[6,370],[6,371],[6,371],[6,372],[6,372],[6,373],[6,373],[6,374],[6,374],[6,375],[6,375],[6,376],[6,376],[6,377],[6,377],[6,378],[6,378],[6,379],[6,379],[6,380],[6,380],[6,381],[6,381],[6,382],[6,382],[6,383],[6,383],[6,384],[6,384],[6,385],[6,385],[6,386],[6,386],[6,387],[6,387],[6,388],[6,388],[6,389],[6,389],[6,390],[6,390],[6,391],[6,391],[6,392],[6,392],[6,393],[6,393],[6,394],[6,394],[6,395],[6,395],[6,396],[6,396],[6,397],[6,397],[6,398],[6,398],[6,399],[6,399],[6,400],[6,400],[6,401],[6,401],[6,402],[6,402],[6,403],[6,403],[6,404],[6,404],[6,405],[6,405],[6,406],[6,406],[6,407],[6,407],[6,408],[6,408],[6,409],[6,409],[6,410],[6,410],[6,411],[6,411],[6,412],[6,412],[6,413],[6,413],[6,414],[6,414],[6,415],[6,415],[6,416],[6,416],[6,417],[6,417],[6,418],[6,418],[6,419],[6,419],[6,420],[6,420],[6,421],[6,421],[6,422],[6,422],[6,423],[6,423],[6,424],[6,424],[6,425],[6,425],[6,426],[6,426],[6,427],[6,427],[6,428],[6,428],[6,429],[6,429],[6,430],[6,430],[6,431],[6,431],[6,432],[6,432],[6,433],[6,433],[6,434],[6,434],[6,435],[6,435],[6,436],[6,436],[6,437],[6,437],[6,438],[6,438],[6,439],[6,439],[6,440],[6,440],[6,441],[6,441],[6,442],[6,442],[6,443],[6,443],[6,444],[6,444],[6,445],[6,445],[6,446],[6,446],[6,447],[6,447],[6,448],[6,448],[6,449],[6,449],[6,450],[6,450],[6,451],[6,451],[6,452],[6,452],[6,453],[6,453],[6,454],[6,454],[6,455],[6,455],[6,456],[6,456],[6,457],[6,457],[6,458],[6,458],[6,459],[6,459],[6,460],[6,460],[6,461],[6,461],[6,462],[6,462],[6,463],[6,463],[6,464],[6,464],[6,465],[6,465],[6,466],[6,466],[6,467],[6,467],[6,468],[6,468],[6,469],[6,469],[6,470],[6,470],[6,471],[6,471],[6,472],[6,472],[6,473],[6,473],[6,474],[6,474],[6,475],[6,475],[6,476],[6,476],[6,477],[6,477],[6,478],[6,478],[6,479],[6,479],[6,480],[6,480],[6,481],[6,481],[6,482],[6,482],[6,483],[6,483],[6,484],[6,484],[6,485],[6,485],[6,486],[6,486],[6,487],[6,487],[6,488],[6,488],[6,489],[6,489],[6,490],[6,490],[6,491],[6,491],[6,492],[6,492],[6,493],[6,493],[6,494],[6,494],[6,495],[6,495],[6,496],[6,496],[6,497],[6,497],[6,498],[6,498],[6,499],[6,499],[6,500],[6,500],[7,2],[7,2],[7,3],[7,3],[7,4],[7,4],[7,5],[7,5],[7,6],[7,6],[7,7],[7,7],[7,8],[7,8],[7,9],[7,9],[7,10],[7,10],[7,11],[7,11],[7,12],[7,12],[7,13],[7,13],[7,14],[7,14],[7,15],[7,15],[7,16],[7,16],[7,17],[7,17],[7,18],[7,18],[7,19],[7,19],[7,20],[7,20],[7,21],[7,21],[7,22],[7,22],[7,23],[7,23],[7,24],[7,24],[7,25],[7,25],[7,26],[7,26],[7,27],[7,27],[7,28],[7,28],[7,29],[7,29],[7,30],[7,30],[7,31],[7,31],[7,32],[7,32],[7,33],[7,33],[7,34],[7,34],[7,35],[7,35],[7,36],[7,36],[7,37],[7,37],[7,38],[7,38],[7,39],[7,39],[7,40],[7,40],[7,41],[7,41],[7,42],[7,42],[7,43],[7,43],[7,44],[7,44],[7,45],[7,45],[7,46],[7,46],[7,47],[7,47],[7,48],[7,48],[7,49],[7,49],[7,50],[7,50],[7,51],[7,51],[7,52],[7,52],[7,53],[7,53],[7,54],[7,54],[7,55],[7,55],[7,56],[7,56],[7,57],[7,57],[7,58],[7,58],[7,59],[7,59],[7,60],[7,60],[7,61],[7,61],[7,62],[7,62],[7,63],[7,63],[7,64],[7,64],[7,65],[7,65],[7,66],[7,66],[7,67],[7,67],[7,68],[7,68],[7,69],[7,69],[7,70],[7,70],[7,71],[7,71],[7,72],[7,72],[7,73],[7,73],[7,74],[7,74],[7,75],[7,75],[7,76],[7,76],[7,77],[7,77],[7,78],[7,78],[7,79],[7,79],[7,80],[7,80],[7,81],[7,81],[7,82],[7,82],[7,83],[7,83],[7,84],[7,84],[7,85],[7,85],[7,86],[7,86],[7,87],[7,87],[7,88],[7,88],[7,89],[7,89],[7,90],[7,90],[7,91],[7,91],[7,92],[7,92],[7,93],[7,93],[7,94],[7,94],[7,95],[7,95],[7,96],[7,96],[7,97],[7,97],[7,98],[7,98],[7,99],[7,99],[7,100],[7,100],[7,101],[7,101],[7,102],[7,102],[7,103],[7,103],[7,104],[7,104],[7,105],[7,105],[7,106],[7,106],[7,107],[7,107],[7,108],[7,108],[7,109],[7,109],[7,110],[7,110],[7,111],[7,111],[7,112],[7,112],[7,113],[7,113],[7,114],[7,114],[7,115],[7,115],[7,116],[7,116],[7,117],[7,117],[7,118],[7,118],[7,119],[7,119],[7,120],[7,120],[7,121],[7,121],[7,122],[7,122],[7,123],[7,123],[7,124],[7,124],[7,125],[7,125],[7,126],[7,126],[7,127],[7,127],[7,128],[7,128],[7,129],[7,129],[7,130],[7,130],[7,131],[7,131],[7,132],[7,132],[7,133],[7,133],[7,134],[7,134],[7,135],[7,135],[7,136],[7,136],[7,137],[7,137],[7,138],[7,138],[7,139],[7,139],[7,140],[7,140],[7,141],[7,141],[7,142],[7,142],[7,143],[7,143],[7,144],[7,144],[7,145],[7,145],[7,146],[7,146],[7,147],[7,147],[7,148],[7,148],[7,149],[7,149],[7,150],[7,150],[7,151],[7,151],[7,152],[7,152],[7,153],[7,153],[7,154],[7,154],[7,155],[7,155],[7,156],[7,156],[7,157],[7,157],[7,158],[7,158],[7,159],[7,159],[7,160],[7,160],[7,161],[7,161],[7,162],[7,162],[7,163],[7,163],[7,164],[7,164],[7,165],[7,165],[7,166],[7,166],[7,167],[7,167],[7,168],[7,168],[7,169],[7,169],[7,170],[7,170],[7,171],[7,171],[7,172],[7,172],[7,173],[7,173],[7,174],[7,174],[7,175],[7,175],[7,176],[7,176],[7,177],[7,177],[7,178],[7,178],[7,179],[7,179],[7,180],[7,180],[7,181],[7,181],[7,182],[7,182],[7,183],[7,183],[7,184],[7,184],[7,185],[7,185],[7,186],[7,186],[7,187],[7,187],[7,188],[7,188],[7,189],[7,189],[7,190],[7,190],[7,191],[7,191],[7,192],[7,192],[7,193],[7,193],[7,194],[7,194],[7,195],[7,195],[7,196],[7,196],[7,197],[7,197],[7,198],[7,198],[7,199],[7,199],[7,200],[7,200],[7,201],[7,201],[7,202],[7,202],[7,203],[7,203],[7,204],[7,204],[7,205],[7,205],[7,206],[7,206],[7,207],[7,207],[7,208],[7,208],[7,209],[7,209],[7,210],[7,210],[7,211],[7,211],[7,212],[7,212],[7,213],[7,213],[7,214],[7,214],[7,215],[7,215],[7,216],[7,216],[7,217],[7,217],[7,218],[7,218],[7,219],[7,219],[7,220],[7,220],[7,221],[7,221],[7,222],[7,222],[7,223],[7,223],[7,224],[7,224],[7,225],[7,225],[7,226],[7,226],[7,227],[7,227],[7,228],[7,228],[7,229],[7,229],[7,230],[7,230],[7,231],[7,231],[7,232],[7,232],[7,233],[7,233],[7,234],[7,234],[7,235],[7,235],[7,236],[7,236],[7,237],[7,237],[7,238],[7,238],[7,239],[7,239],[7,240],[7,240],[7,241],[7,241],[7,242],[7,242],[7,243],[7,243],[7,244],[7,244],[7,245],[7,245],[7,246],[7,246],[7,247],[7,247],[7,248],[7,248],[7,249],[7,249],[7,250],[7,250],[7,251],[7,251],[7,252],[7,252],[7,253],[7,253],[7,254],[7,254],[7,255],[7,255],[7,256],[7,256],[7,257],[7,257],[7,258],[7,258],[7,259],[7,259],[7,260],[7,260],[7,261],[7,261],[7,262],[7,262],[7,263],[7,263],[7,264],[7,264],[7,265],[7,265],[7,266],[7,266],[7,267],[7,267],[7,268],[7,268],[7,269],[7,269],[7,270],[7,270],[7,271],[7,271],[7,272],[7,272],[7,273],[7,273],[7,274],[7,274],[7,275],[7,275],[7,276],[7,276],[7,277],[7,277],[7,278],[7,278],[7,279],[7,279],[7,280],[7,280],[7,281],[7,281],[7,282],[7,282],[7,283],[7,283],[7,284],[7,284],[7,285],[7,285],[7,286],[7,286],[7,287],[7,287],[7,288],[7,288],[7,289],[7,289],[7,290],[7,290],[7,291],[7,291],[7,292],[7,292],[7,293],[7,293],[7,294],[7,294],[7,295],[7,295],[7,296],[7,296],[7,297],[7,297],[7,298],[7,298],[7,299],[7,299],[7,300],[7,300],[7,301],[7,301],[7,302],[7,302],[7,303],[7,303],[7,304],[7,304],[7,305],[7,305],[7,306],[7,306],[7,307],[7,307],[7,308],[7,308],[7,309],[7,309],[7,310],[7,310],[7,311],[7,311],[7,312],[7,312],[7,313],[7,313],[7,314],[7,314],[7,315],[7,315],[7,316],[7,316],[7,317],[7,317],[7,318],[7,318],[7,319],[7,319],[7,320],[7,320],[7,321],[7,321],[7,322],[7,322],[7,323],[7,323],[7,324],[7,324],[7,325],[7,325],[7,326],[7,326],[7,327],[7,327],[7,328],[7,328],[7,329],[7,329],[7,330],[7,330],[7,331],[7,331],[7,332],[7,332],[7,333],[7,333],[7,334],[7,334],[7,335],[7,335],[7,336],[7,336],[7,337],[7,337],[7,338],[7,338],[7,339],[7,339],[7,340],[7,340],[7,341],[7,341],[7,342],[7,342],[7,343],[7,343],[7,344],[7,344],[7,345],[7,345],[7,346],[7,346],[7,347],[7,347],[7,348],[7,348],[7,349],[7,349],[7,350],[7,350],[7,351],[7,351],[7,352],[7,352],[7,353],[7,353],[7,354],[7,354],[7,355],[7,355],[7,356],[7,356],[7,357],[7,357],[7,358],[7,358],[7,359],[7,359],[7,360],[7,360],[7,361],[7,361],[7,362],[7,362],[7,363],[7,363],[7,364],[7,364],[7,365],[7,365],[7,366],[7,366],[7,367],[7,367],[7,368],[7,368],[7,369],[7,369],[7,370],[7,370],[7,371],[7,371],[7,372],[7,372],[7,373],[7,373],[7,374],[7,374],[7,375],[7,375],[7,376],[7,376],[7,377],[7,377],[7,378],[7,378],[7,379],[7,379],[7,380],[7,380],[7,381],[7,381],[7,382],[7,382],[7,383],[7,383],[7,384],[7,384],[7,385],[7,385],[7,386],[7,386],[7,387],[7,387],[7,388],[7,388],[7,389],[7,389],[7,390],[7,390],[7,391],[7,391],[7,392],[7,392],[7,393],[7,393],[7,394],[7,394],[7,395],[7,395],[7,396],[7,396],[7,397],[7,397],[7,398],[7,398],[7,399],[7,399],[7,400],[7,400],[7,401],[7,401],[7,402],[7,402],[7,403],[7,403],[7,404],[7,404],[7,405],[7,405],[7,406],[7,406],[7,407],[7,407],[7,408],[7,408],[7,409],[7,409],[7,410],[7,410],[7,411],[7,411],[7,412],[7,412],[7,413],[7,413],[7,414],[7,414],[7,415],[7,415],[7,416],[7,416],[7,417],[7,417],[7,418],[7,418],[7,419],[7,419],[7,420],[7,420],[7,421],[7,421],[7,422],[7,422],[7,423],[7,423],[7,424],[7,424],[7,425],[7,425],[7,426],[7,426],[7,427],[7,427],[7,428],[7,428],[7,429],[7,429],[7,430],[7,430],[7,431],[7,431],[7,432],[7,432],[7,433],[7,433],[7,434],[7,434],[7,435],[7,435],[7,436],[7,436],[7,437],[7,437],[7,438],[7,438],[7,439],[7,439],[7,440],[7,440],[7,441],[7,441],[7,442],[7,442],[7,443],[7,443],[7,444],[7,444],[7,445],[7,445],[7,446],[7,446],[7,447],[7,447],[7,448],[7,448],[7,449],[7,449],[7,450],[7,450],[7,451],[7,451],[7,452],[7,452],[7,453],[7,453],[7,454],[7,454],[7,455],[7,455],[7,456],[7,456],[7,457],[7,457],[7,458],[7,458],[7,459],[7,459],[7,460],[7,460],[7,461],[7,461],[7,462],[7,462],[7,463],[7,463],[7,464],[7,464],[7,465],[7,465],[7,466],[7,466],[7,467],[7,467],[7,468],[7,468],[7,469],[7,469],[7,470],[7,470],[7,471],[7,471],[7,472],[7,472],[7,473],[7,473],[7,474],[7,474],[7,475],[7,475],[7,476],[7,476],[7,477],[7,477],[7,478],[7,478],[7,479],[7,479],[7,480],[7,480],[7,481],[7,481],[7,482],[7,482],[7,483],[7,483],[7,484],[7,484],[7,485],[7,485],[7,486],[7,486],[7,487],[7,487],[7,488],[7,488],[7,489],[7,489],[7,490],[7,490],[7,491],[7,491],[7,492],[7,492],[7,493],[7,493],[7,494],[7,494],[7,495],[7,495],[7,496],[7,496],[7,497],[7,497],[7,498],[7,498],[7,499],[7,499],[7,500],[7,500],[8,2],[8,2],[8,3],[8,3],[8,4],[8,4],[8,5],[8,5],[8,6],[8,6],[8,7],[8,7],[8,8],[8,8],[8,9],[8,9],[8,10],[8,10],[8,11],[8,11],[8,12],[8,12],[8,13],[8,13],[8,14],[8,14],[8,15],[8,15],[8,16],[8,16],[8,17],[8,17],[8,18],[8,18],[8,19],[8,19],[8,20],[8,20],[8,21],[8,21],[8,22],[8,22],[8,23],[8,23],[8,24],[8,24],[8,25],[8,25],[8,26],[8,26],[8,27],[8,27],[8,28],[8,28],[8,29],[8,29],[8,30],[8,30],[8,31],[8,31],[8,32],[8,32],[8,33],[8,33],[8,34],[8,34],[8,35],[8,35],[8,36],[8,36],[8,37],[8,37],[8,38],[8,38],[8,39],[8,39],[8,40],[8,40],[8,41],[8,41],[8,42],[8,42],[8,43],[8,43],[8,44],[8,44],[8,45],[8,45],[8,46],[8,46],[8,47],[8,47],[8,48],[8,48],[8,49],[8,49],[8,50],[8,50],[8,51],[8,51],[8,52],[8,52],[8,53],[8,53],[8,54],[8,54],[8,55],[8,55],[8,56],[8,56],[8,57],[8,57],[8,58],[8,58],[8,59],[8,59],[8,60],[8,60],[8,61],[8,61],[8,62],[8,62],[8,63],[8,63],[8,64],[8,64],[8,65],[8,65],[8,66],[8,66],[8,67],[8,67],[8,68],[8,68],[8,69],[8,69],[8,70],[8,70],[8,71],[8,71],[8,72],[8,72],[8,73],[8,73],[8,74],[8,74],[8,75],[8,75],[8,76],[8,76],[8,77],[8,77],[8,78],[8,78],[8,79],[8,79],[8,80],[8,80],[8,81],[8,81],[8,82],[8,82],[8,83],[8,83],[8,84],[8,84],[8,85],[8,85],[8,86],[8,86],[8,87],[8,87],[8,88],[8,88],[8,89],[8,89],[8,90],[8,90],[8,91],[8,91],[8,92],[8,92],[8,93],[8,93],[8,94],[8,94],[8,95],[8,95],[8,96],[8,96],[8,97],[8,97],[8,98],[8,98],[8,99],[8,99],[8,100],[8,100],[8,101],[8,101],[8,102],[8,102],[8,103],[8,103],[8,104],[8,104],[8,105],[8,105],[8,106],[8,106],[8,107],[8,107],[8,108],[8,108],[8,109],[8,109],[8,110],[8,110],[8,111],[8,111],[8,112],[8,112],[8,113],[8,113],[8,114],[8,114],[8,115],[8,115],[8,116],[8,116],[8,117],[8,117],[8,118],[8,118],[8,119],[8,119],[8,120],[8,120],[8,121],[8,121],[8,122],[8,122],[8,123],[8,123],[8,124],[8,124],[8,125],[8,125],[8,126],[8,126],[8,127],[8,127],[8,128],[8,128],[8,129],[8,129],[8,130],[8,130],[8,131],[8,131],[8,132],[8,132],[8,133],[8,133],[8,134],[8,134],[8,135],[8,135],[8,136],[8,136],[8,137],[8,137],[8,138],[8,138],[8,139],[8,139],[8,140],[8,140],[8,141],[8,141],[8,142],[8,142],[8,143],[8,143],[8,144],[8,144],[8,145],[8,145],[8,146],[8,146],[8,147],[8,147],[8,148],[8,148],[8,149],[8,149],[8,150],[8,150],[8,151],[8,151],[8,152],[8,152],[8,153],[8,153],[8,154],[8,154],[8,155],[8,155],[8,156],[8,156],[8,157],[8,157],[8,158],[8,158],[8,159],[8,159],[8,160],[8,160],[8,161],[8,161],[8,162],[8,162],[8,163],[8,163],[8,164],[8,164],[8,165],[8,165],[8,166],[8,166],[8,167],[8,167],[8,168],[8,168],[8,169],[8,169],[8,170],[8,170],[8,171],[8,171],[8,172],[8,172],[8,173],[8,173],[8,174],[8,174],[8,175],[8,175],[8,176],[8,176],[8,177],[8,177],[8,178],[8,178],[8,179],[8,179],[8,180],[8,180],[8,181],[8,181],[8,182],[8,182],[8,183],[8,183],[8,184],[8,184],[8,185],[8,185],[8,186],[8,186],[8,187],[8,187],[8,188],[8,188],[8,189],[8,189],[8,190],[8,190],[8,191],[8,191],[8,192],[8,192],[8,193],[8,193],[8,194],[8,194],[8,195],[8,195],[8,196],[8,196],[8,197],[8,197],[8,198],[8,198],[8,199],[8,199],[8,200],[8,200],[8,201],[8,201],[8,202],[8,202],[8,203],[8,203],[8,204],[8,204],[8,205],[8,205],[8,206],[8,206],[8,207],[8,207],[8,208],[8,208],[8,209],[8,209],[8,210],[8,210],[8,211],[8,211],[8,212],[8,212],[8,213],[8,213],[8,214],[8,214],[8,215],[8,215],[8,216],[8,216],[8,217],[8,217],[8,218],[8,218],[8,219],[8,219],[8,220],[8,220],[8,221],[8,221],[8,222],[8,222],[8,223],[8,223],[8,224],[8,224],[8,225],[8,225],[8,226],[8,226],[8,227],[8,227],[8,228],[8,228],[8,229],[8,229],[8,230],[8,230],[8,231],[8,231],[8,232],[8,232],[8,233],[8,233],[8,234],[8,234],[8,235],[8,235],[8,236],[8,236],[8,237],[8,237],[8,238],[8,238],[8,239],[8,239],[8,240],[8,240],[8,241],[8,241],[8,242],[8,242],[8,243],[8,243],[8,244],[8,244],[8,245],[8,245],[8,246],[8,246],[8,247],[8,247],[8,248],[8,248],[8,249],[8,249],[8,250],[8,250],[8,251],[8,251],[8,252],[8,252],[8,253],[8,253],[8,254],[8,254],[8,255],[8,255],[8,256],[8,256],[8,257],[8,257],[8,258],[8,258],[8,259],[8,259],[8,260],[8,260],[8,261],[8,261],[8,262],[8,262],[8,263],[8,263],[8,264],[8,264],[8,265],[8,265],[8,266],[8,266],[8,267],[8,267],[8,268],[8,268],[8,269],[8,269],[8,270],[8,270],[8,271],[8,271],[8,272],[8,272],[8,273],[8,273],[8,274],[8,274],[8,275],[8,275],[8,276],[8,276],[8,277],[8,277],[8,278],[8,278],[8,279],[8,279],[8,280],[8,280],[8,281],[8,281],[8,282],[8,282],[8,283],[8,283],[8,284],[8,284],[8,285],[8,285],[8,286],[8,286],[8,287],[8,287],[8,288],[8,288],[8,289],[8,289],[8,290],[8,290],[8,291],[8,291],[8,292],[8,292],[8,293],[8,293],[8,294],[8,294],[8,295],[8,295],[8,296],[8,296],[8,297],[8,297],[8,298],[8,298],[8,299],[8,299],[8,300],[8,300],[8,301],[8,301],[8,302],[8,302],[8,303],[8,303],[8,304],[8,304],[8,305],[8,305],[8,306],[8,306],[8,307],[8,307],[8,308],[8,308],[8,309],[8,309],[8,310],[8,310],[8,311],[8,311],[8,312],[8,312],[8,313],[8,313],[8,314],[8,314],[8,315],[8,315],[8,316],[8,316],[8,317],[8,317],[8,318],[8,318],[8,319],[8,319],[8,320],[8,320],[8,321],[8,321],[8,322],[8,322],[8,323],[8,323],[8,324],[8,324],[8,325],[8,325],[8,326],[8,326],[8,327],[8,327],[8,328],[8,328],[8,329],[8,329],[8,330],[8,330],[8,331],[8,331],[8,332],[8,332],[8,333],[8,333],[8,334],[8,334],[8,335],[8,335],[8,336],[8,336],[8,337],[8,337],[8,338],[8,338],[8,339],[8,339],[8,340],[8,340],[8,341],[8,341],[8,342],[8,342],[8,343],[8,343],[8,344],[8,344],[8,345],[8,345],[8,346],[8,346],[8,347],[8,347],[8,348],[8,348],[8,349],[8,349],[8,350],[8,350],[8,351],[8,351],[8,352],[8,352],[8,353],[8,353],[8,354],[8,354],[8,355],[8,355],[8,356],[8,356],[8,357],[8,357],[8,358],[8,358],[8,359],[8,359],[8,360],[8,360],[8,361],[8,361],[8,362],[8,362],[8,363],[8,363],[8,364],[8,364],[8,365],[8,365],[8,366],[8,366],[8,367],[8,367],[8,368],[8,368],[8,369],[8,369],[8,370],[8,370],[8,371],[8,371],[8,372],[8,372],[8,373],[8,373],[8,374],[8,374],[8,375],[8,375],[8,376],[8,376],[8,377],[8,377],[8,378],[8,378],[8,379],[8,379],[8,380],[8,380],[8,381],[8,381],[8,382],[8,382],[8,383],[8,383],[8,384],[8,384],[8,385],[8,385],[8,386],[8,386],[8,387],[8,387],[8,388],[8,388],[8,389],[8,389],[8,390],[8,390],[8,391],[8,391],[8,392],[8,392],[8,393],[8,393],[8,394],[8,394],[8,395],[8,395],[8,396],[8,396],[8,397],[8,397],[8,398],[8,398],[8,399],[8,399],[8,400],[8,400],[8,401],[8,401],[8,402],[8,402],[8,403],[8,403],[8,404],[8,404],[8,405],[8,405],[8,406],[8,406],[8,407],[8,407],[8,408],[8,408],[8,409],[8,409],[8,410],[8,410],[8,411],[8,411],[8,412],[8,412],[8,413],[8,413],[8,414],[8,414],[8,415],[8,415],[8,416],[8,416],[8,417],[8,417],[8,418],[8,418],[8,419],[8,419],[8,420],[8,420],[8,421],[8,421],[8,422],[8,422],[8,423],[8,423],[8,424],[8,424],[8,425],[8,425],[8,426],[8,426],[8,427],[8,427],[8,428],[8,428],[8,429],[8,429],[8,430],[8,430],[8,431],[8,431],[8,432],[8,432],[8,433],[8,433],[8,434],[8,434],[8,435],[8,435],[8,436],[8,436],[8,437],[8,437],[8,438],[8,438],[8,439],[8,439],[8,440],[8,440],[8,441],[8,441],[8,442],[8,442],[8,443],[8,443],[8,444],[8,444],[8,445],[8,445],[8,446],[8,446],[8,447],[8,447],[8,448],[8,448],[8,449],[8,449],[8,450],[8,450],[8,451],[8,451],[8,452],[8,452],[8,453],[8,453],[8,454],[8,454],[8,455],[8,455],[8,456],[8,456],[8,457],[8,457],[8,458],[8,458],[8,459],[8,459],[8,460],[8,460],[8,461],[8,461],[8,462],[8,462],[8,463],[8,463],[8,464],[8,464],[8,465],[8,465],[8,466],[8,466],[8,467],[8,467],[8,468],[8,468],[8,469],[8,469],[8,470],[8,470],[8,471],[8,471],[8,472],[8,472],[8,473],[8,473],[8,474],[8,474],[8,475],[8,475],[8,476],[8,476],[8,477],[8,477],[8,478],[8,478],[8,479],[8,479],[8,480],[8,480],[8,481],[8,481],[8,482],[8,482],[8,483],[8,483],[8,484],[8,484],[8,485],[8,485],[8,486],[8,486],[8,487],[8,487],[8,488],[8,488],[8,489],[8,489],[8,490],[8,490],[8,491],[8,491],[8,492],[8,492],[8,493],[8,493],[8,494],[8,494],[8,495],[8,495],[8,496],[8,496],[8,497],[8,497],[8,498],[8,498],[8,499],[8,499],[8,500],[8,500],[21,2],[21,2]],\"22,4\":[[0,2],[0,2],[0,2],[0,2],[0,2],[0,3],[0,3],[0,3],[0,3],[0,3],[0,4],[0,4],[0,4],[0,4],[0,4],[0,5],[0,5],[0,5],[0,5],[0,5],[0,6],[0,6],[0,6],[0,6],[0,6],[0,7],[0,7],[0,7],[0,7],[0,7],[0,8],[0,8],[0,8],[0,8],[0,8],[0,9],[0,9],[0,9],[0,9],[0,9],[0,10],[0,10],[0,10],[0,10],[0,10],[0,11],[0,11],[0,11],[0,11],[0,11],[0,12],[0,12],[0,12],[0,12],[0,12],[0,13],[0,13],[0,13],[0,13],[0,13],[0,14],[0,14],[0,14],[0,14],[0,14],[0,15],[0,15],[0,15],[0,15],[0,15],[0,16],[0,16],[0,16],[0,16],[0,16],[0,17],[0,17],[0,17],[0,17],[0,17],[0,18],[0,18],[0,18],[0,18],[0,18],[0,19],[0,19],[0,19],[0,19],[0,19],[0,20],[0,20],[0,20],[0,20],[0,20],[0,21],[0,21],[0,21],[0,21],[0,21],[0,22],[0,22],[0,22],[0,22],[0,22],[0,23],[0,23],[0,23],[0,23],[0,23],[0,24],[0,24],[0,24],[0,24],[0,24],[0,25],[0,25],[0,25],[0,25],[0,25],[0,26],[0,26],[0,26],[0,26],[0,26],[0,27],[0,27],[0,27],[0,27],[0,27],[0,28],[0,28],[0,28],[0,28],[0,28],[0,29],[0,29],[0,29],[0,29],[0,29],[0,30],[0,30],[0,30],[0,30],[0,30],[0,31],[0,31],[0,31],[0,31],[0,31],[0,32],[0,32],[0,32],[0,32],[0,32],[0,33],[0,33],[0,33],[0,33],[0,33],[0,34],[0,34],[0,34],[0,34],[0,34],[0,35],[0,35],[0,35],[0,35],[0,35],[0,36],[0,36],[0,36],[0,36],[0,36],[0,37],[0,37],[0,37],[0,37],[0,37],[0,38],[0,38],[0,38],[0,38],[0,38],[0,39],[0,39],[0,39],[0,39],[0,39],[0,40],[0,40],[0,40],[0,40],[0,40],[0,41],[0,41],[0,41],[0,41],[0,41],[0,42],[0,42],[0,42],[0,42],[0,42],[0,43],[0,43],[0,43],[0,43],[0,43],[0,44],[0,44],[0,44],[0,44],[0,44],[0,45],[0,45],[0,45],[0,45],[0,45],[0,46],[0,46],[0,46],[0,46],[0,46],[0,47],[0,47],[0,47],[0,47],[0,47],[0,48],[0,48],[0,48],[0,48],[0,48],[0,49],[0,49],[0,49],[0,49],[0,49],[0,50],[0,50],[0,50],[0,50],[0,50],[0,51],[0,51],[0,51],[0,51],[0,51],[0,52],[0,52],[0,52],[0,52],[0,52],[0,53],[0,53],[0,53],[0,53],[0,53],[0,54],[0,54],[0,54],[0,54],[0,54],[0,55],[0,55],[0,55],[0,55],[0,55],[0,56],[0,56],[0,56],[0,56],[0,56],[0,57],[0,57],[0,57],[0,57],[0,57],[0,58],[0,58],[0,58],[0,58],[0,58],[0,59],[0,59],[0,59],[0,59],[0,59],[0,60],[0,60],[0,60],[0,60],[0,60],[0,61],[0,61],[0,61],[0,61],[0,61],[0,62],[0,62],[0,62],[0,62],[0,62],[0,63],[0,63],[0,63],[0,63],[0,63],[0,64],[0,64],[0,64],[0,64],[0,64],[0,65],[0,65],[0,65],[0,65],[0,65],[0,66],[0,66],[0,66],[0,66],[0,66],[0,67],[0,67],[0,67],[0,67],[0,67],[0,68],[0,68],[0,68],[0,68],[0,68],[0,69],[0,69],[0,69],[0,69],[0,69],[0,70],[0,70],[0,70],[0,70],[0,70],[0,71],[0,71],[0,71],[0,71],[0,71],[0,72],[0,72],[0,72],[0,72],[0,72],[0,73],[0,73],[0,73],[0,73],[0,73],[0,74],[0,74],[0,74],[0,74],[0,74],[0,75],[0,75],[0,75],[0,75],[0,75],[0,76],[0,76],[0,76],[0,76],[0,76],[0,77],[0,77],[0,77],[0,77],[0,77],[0,78],[0,78],[0,78],[0,78],[0,78],[0,79],[0,79],[0,79],[0,79],[0,79],[0,80],[0,80],[0,80],[0,80],[0,80],[0,81],[0,81],[0,81],[0,81],[0,81],[0,82],[0,82],[0,82],[0,82],[0,82],[0,83],[0,83],[0,83],[0,83],[0,83],[0,84],[0,84],[0,84],[0,84],[0,84],[0,85],[0,85],[0,85],[0,85],[0,85],[0,86],[0,86],[0,86],[0,86],[0,86],[0,87],[0,87],[0,87],[0,87],[0,87],[0,88],[0,88],[0,88],[0,88],[0,88],[0,89],[0,89],[0,89],[0,89],[0,89],[0,90],[0,90],[0,90],[0,90],[0,90],[0,91],[0,91],[0,91],[0,91],[0,91],[0,92],[0,92],[0,92],[0,92],[0,92],[0,93],[0,93],[0,93],[0,93],[0,93],[0,94],[0,94],[0,94],[0,94],[0,94],[0,95],[0,95],[0,95],[0,95],[0,95],[0,96],[0,96],[0,96],[0,96],[0,96],[0,97],[0,97],[0,97],[0,97],[0,97],[0,98],[0,98],[0,98],[0,98],[0,98],[0,99],[0,99],[0,99],[0,99],[0,99],[0,100],[0,100],[0,100],[0,100],[0,100],[0,101],[0,101],[0,101],[0,101],[0,101],[0,102],[0,102],[0,102],[0,102],[0,102],[0,103],[0,103],[0,103],[0,103],[0,103],[0,104],[0,104],[0,104],[0,104],[0,104],[0,105],[0,105],[0,105],[0,105],[0,105],[0,106],[0,106],[0,106],[0,106],[0,106],[0,107],[0,107],[0,107],[0,107],[0,107],[0,108],[0,108],[0,108],[0,108],[0,108],[0,109],[0,109],[0,109],[0,109],[0,109],[0,110],[0,110],[0,110],[0,110],[0,110],[0,111],[0,111],[0,111],[0,111],[0,111],[0,112],[0,112],[0,112],[0,112],[0,112],[0,113],[0,113],[0,113],[0,113],[0,113],[0,114],[0,114],[0,114],[0,114],[0,114],[0,115],[0,115],[0,115],[0,115],[0,115],[0,116],[0,116],[0,116],[0,116],[0,116],[0,117],[0,117],[0,117],[0,117],[0,117],[0,118],[0,118],[0,118],[0,118],[0,118],[0,119],[0,119],[0,119],[0,119],[0,119],[0,120],[0,120],[0,120],[0,120],[0,120],[0,121],[0,121],[0,121],[0,121],[0,121],[0,122],[0,122],[0,122],[0,122],[0,122],[0,123],[0,123],[0,123],[0,123],[0,123],[0,124],[0,124],[0,124],[0,124],[0,124],[0,125],[0,125],[0,125],[0,125],[0,125],[0,126],[0,126],[0,126],[0,126],[0,126],[0,127],[0,127],[0,127],[0,127],[0,127],[0,128],[0,128],[0,128],[0,128],[0,128],[0,129],[0,129],[0,129],[0,129],[0,129],[0,130],[0,130],[0,130],[0,130],[0,130],[0,131],[0,131],[0,131],[0,131],[0,131],[0,132],[0,132],[0,132],[0,132],[0,132],[0,133],[0,133],[0,133],[0,133],[0,133],[0,134],[0,134],[0,134],[0,134],[0,134],[0,135],[0,135],[0,135],[0,135],[0,135],[0,136],[0,136],[0,136],[0,136],[0,136],[0,137],[0,137],[0,137],[0,137],[0,137],[0,138],[0,138],[0,138],[0,138],[0,138],[0,139],[0,139],[0,139],[0,139],[0,139],[0,140],[0,140],[0,140],[0,140],[0,140],[0,141],[0,141],[0,141],[0,141],[0,141],[0,142],[0,142],[0,142],[0,142],[0,142],[0,143],[0,143],[0,143],[0,143],[0,143],[0,144],[0,144],[0,144],[0,144],[0,144],[0,145],[0,145],[0,145],[0,145],[0,145],[0,146],[0,146],[0,146],[0,146],[0,146],[0,147],[0,147],[0,147],[0,147],[0,147],[0,148],[0,148],[0,148],[0,148],[0,148],[0,149],[0,149],[0,149],[0,149],[0,149],[0,150],[0,150],[0,150],[0,150],[0,150],[0,151],[0,151],[0,151],[0,151],[0,151],[0,152],[0,152],[0,152],[0,152],[0,152],[0,153],[0,153],[0,153],[0,153],[0,153],[0,154],[0,154],[0,154],[0,154],[0,154],[0,155],[0,155],[0,155],[0,155],[0,155],[0,156],[0,156],[0,156],[0,156],[0,156],[0,157],[0,157],[0,157],[0,157],[0,157],[0,158],[0,158],[0,158],[0,158],[0,158],[0,159],[0,159],[0,159],[0,159],[0,159],[0,160],[0,160],[0,160],[0,160],[0,160],[0,161],[0,161],[0,161],[0,161],[0,161],[0,162],[0,162],[0,162],[0,162],[0,162],[0,163],[0,163],[0,163],[0,163],[0,163],[0,164],[0,164],[0,164],[0,164],[0,164],[0,165],[0,165],[0,165],[0,165],[0,165],[0,166],[0,166],[0,166],[0,166],[0,166],[0,167],[0,167],[0,167],[0,167],[0,167],[0,168],[0,168],[0,168],[0,168],[0,168],[0,169],[0,169],[0,169],[0,169],[0,169],[0,170],[0,170],[0,170],[0,170],[0,170],[0,171],[0,171],[0,171],[0,171],[0,171],[0,172],[0,172],[0,172],[0,172],[0,172],[0,173],[0,173],[0,173],[0,173],[0,173],[0,174],[0,174],[0,174],[0,174],[0,174],[0,175],[0,175],[0,175],[0,175],[0,175],[0,176],[0,176],[0,176],[0,176],[0,176],[0,177],[0,177],[0,177],[0,177],[0,177],[0,178],[0,178],[0,178],[0,178],[0,178],[0,179],[0,179],[0,179],[0,179],[0,179],[0,180],[0,180],[0,180],[0,180],[0,180],[0,181],[0,181],[0,181],[0,181],[0,181],[0,182],[0,182],[0,182],[0,182],[0,182],[0,183],[0,183],[0,183],[0,183],[0,183],[0,184],[0,184],[0,184],[0,184],[0,184],[0,185],[0,185],[0,185],[0,185],[0,185],[0,186],[0,186],[0,186],[0,186],[0,186],[0,187],[0,187],[0,187],[0,187],[0,187],[0,188],[0,188],[0,188],[0,188],[0,188],[0,189],[0,189],[0,189],[0,189],[0,189],[0,190],[0,190],[0,190],[0,190],[0,190],[0,191],[0,191],[0,191],[0,191],[0,191],[0,192],[0,192],[0,192],[0,192],[0,192],[0,193],[0,193],[0,193],[0,193],[0,193],[0,194],[0,194],[0,194],[0,194],[0,194],[0,195],[0,195],[0,195],[0,195],[0,195],[0,196],[0,196],[0,196],[0,196],[0,196],[0,197],[0,197],[0,197],[0,197],[0,197],[0,198],[0,198],[0,198],[0,198],[0,198],[0,199],[0,199],[0,199],[0,199],[0,199],[0,200],[0,200],[0,200],[0,200],[0,200],[0,201],[0,201],[0,201],[0,201],[0,201],[0,202],[0,202],[0,202],[0,202],[0,202],[0,203],[0,203],[0,203],[0,203],[0,203],[0,204],[0,204],[0,204],[0,204],[0,204],[0,205],[0,205],[0,205],[0,205],[0,205],[0,206],[0,206],[0,206],[0,206],[0,206],[0,207],[0,207],[0,207],[0,207],[0,207],[0,208],[0,208],[0,208],[0,208],[0,208],[0,209],[0,209],[0,209],[0,209],[0,209],[0,210],[0,210],[0,210],[0,210],[0,210],[0,211],[0,211],[0,211],[0,211],[0,211],[0,212],[0,212],[0,212],[0,212],[0,212],[0,213],[0,213],[0,213],[0,213],[0,213],[0,214],[0,214],[0,214],[0,214],[0,214],[0,215],[0,215],[0,215],[0,215],[0,215],[0,216],[0,216],[0,216],[0,216],[0,216],[0,217],[0,217],[0,217],[0,217],[0,217],[0,218],[0,218],[0,218],[0,218],[0,218],[0,219],[0,219],[0,219],[0,219],[0,219],[0,220],[0,220],[0,220],[0,220],[0,220],[0,221],[0,221],[0,221],[0,221],[0,221],[0,222],[0,222],[0,222],[0,222],[0,222],[0,223],[0,223],[0,223],[0,223],[0,223],[0,224],[0,224],[0,224],[0,224],[0,224],[0,225],[0,225],[0,225],[0,225],[0,225],[0,226],[0,226],[0,226],[0,226],[0,226],[0,227],[0,227],[0,227],[0,227],[0,227],[0,228],[0,228],[0,228],[0,228],[0,228],[0,229],[0,229],[0,229],[0,229],[0,229],[0,230],[0,230],[0,230],[0,230],[0,230],[0,231],[0,231],[0,231],[0,231],[0,231],[0,232],[0,232],[0,232],[0,232],[0,232],[0,233],[0,233],[0,233],[0,233],[0,233],[0,234],[0,234],[0,234],[0,234],[0,234],[0,235],[0,235],[0,235],[0,235],[0,235],[0,236],[0,236],[0,236],[0,236],[0,236],[0,237],[0,237],[0,237],[0,237],[0,237],[0,238],[0,238],[0,238],[0,238],[0,238],[0,239],[0,239],[0,239],[0,239],[0,239],[0,240],[0,240],[0,240],[0,240],[0,240],[0,241],[0,241],[0,241],[0,241],[0,241],[0,242],[0,242],[0,242],[0,242],[0,242],[0,243],[0,243],[0,243],[0,243],[0,243],[0,244],[0,244],[0,244],[0,244],[0,244],[0,245],[0,245],[0,245],[0,245],[0,245],[0,246],[0,246],[0,246],[0,246],[0,246],[0,247],[0,247],[0,247],[0,247],[0,247],[0,248],[0,248],[0,248],[0,248],[0,248],[0,249],[0,249],[0,249],[0,249],[0,249],[0,250],[0,250],[0,250],[0,250],[0,250],[0,251],[0,251],[0,251],[0,251],[0,251],[0,252],[0,252],[0,252],[0,252],[0,252],[0,253],[0,253],[0,253],[0,253],[0,253],[0,254],[0,254],[0,254],[0,254],[0,254],[0,255],[0,255],[0,255],[0,255],[0,255],[0,256],[0,256],[0,256],[0,256],[0,256],[0,257],[0,257],[0,257],[0,257],[0,257],[0,258],[0,258],[0,258],[0,258],[0,258],[0,259],[0,259],[0,259],[0,259],[0,259],[0,260],[0,260],[0,260],[0,260],[0,260],[0,261],[0,261],[0,261],[0,261],[0,261],[0,262],[0,262],[0,262],[0,262],[0,262],[0,263],[0,263],[0,263],[0,263],[0,263],[0,264],[0,264],[0,264],[0,264],[0,264],[0,265],[0,265],[0,265],[0,265],[0,265],[0,266],[0,266],[0,266],[0,266],[0,266],[0,267],[0,267],[0,267],[0,267],[0,267],[0,268],[0,268],[0,268],[0,268],[0,268],[0,269],[0,269],[0,269],[0,269],[0,269],[0,270],[0,270],[0,270],[0,270],[0,270],[0,271],[0,271],[0,271],[0,271],[0,271],[0,272],[0,272],[0,272],[0,272],[0,272],[0,273],[0,273],[0,273],[0,273],[0,273],[0,274],[0,274],[0,274],[0,274],[0,274],[0,275],[0,275],[0,275],[0,275],[0,275],[0,276],[0,276],[0,276],[0,276],[0,276],[0,277],[0,277],[0,277],[0,277],[0,277],[0,278],[0,278],[0,278],[0,278],[0,278],[0,279],[0,279],[0,279],[0,279],[0,279],[0,280],[0,280],[0,280],[0,280],[0,280],[0,281],[0,281],[0,281],[0,281],[0,281],[0,282],[0,282],[0,282],[0,282],[0,282],[0,283],[0,283],[0,283],[0,283],[0,283],[0,284],[0,284],[0,284],[0,284],[0,284],[0,285],[0,285],[0,285],[0,285],[0,285],[0,286],[0,286],[0,286],[0,286],[0,286],[0,287],[0,287],[0,287],[0,287],[0,287],[0,288],[0,288],[0,288],[0,288],[0,288],[0,289],[0,289],[0,289],[0,289],[0,289],[0,290],[0,290],[0,290],[0,290],[0,290],[0,291],[0,291],[0,291],[0,291],[0,291],[0,292],[0,292],[0,292],[0,292],[0,292],[0,293],[0,293],[0,293],[0,293],[0,293],[0,294],[0,294],[0,294],[0,294],[0,294],[0,295],[0,295],[0,295],[0,295],[0,295],[0,296],[0,296],[0,296],[0,296],[0,296],[0,297],[0,297],[0,297],[0,297],[0,297],[0,298],[0,298],[0,298],[0,298],[0,298],[0,299],[0,299],[0,299],[0,299],[0,299],[0,300],[0,300],[0,300],[0,300],[0,300],[0,301],[0,301],[0,301],[0,301],[0,301],[0,302],[0,302],[0,302],[0,302],[0,302],[0,303],[0,303],[0,303],[0,303],[0,303],[0,304],[0,304],[0,304],[0,304],[0,304],[0,305],[0,305],[0,305],[0,305],[0,305],[0,306],[0,306],[0,306],[0,306],[0,306],[0,307],[0,307],[0,307],[0,307],[0,307],[0,308],[0,308],[0,308],[0,308],[0,308],[0,309],[0,309],[0,309],[0,309],[0,309],[0,310],[0,310],[0,310],[0,310],[0,310],[0,311],[0,311],[0,311],[0,311],[0,311],[0,312],[0,312],[0,312],[0,312],[0,312],[0,313],[0,313],[0,313],[0,313],[0,313],[0,314],[0,314],[0,314],[0,314],[0,314],[0,315],[0,315],[0,315],[0,315],[0,315],[0,316],[0,316],[0,316],[0,316],[0,316],[0,317],[0,317],[0,317],[0,317],[0,317],[0,318],[0,318],[0,318],[0,318],[0,318],[0,319],[0,319],[0,319],[0,319],[0,319],[0,320],[0,320],[0,320],[0,320],[0,320],[0,321],[0,321],[0,321],[0,321],[0,321],[0,322],[0,322],[0,322],[0,322],[0,322],[0,323],[0,323],[0,323],[0,323],[0,323],[0,324],[0,324],[0,324],[0,324],[0,324],[0,325],[0,325],[0,325],[0,325],[0,325],[0,326],[0,326],[0,326],[0,326],[0,326],[0,327],[0,327],[0,327],[0,327],[0,327],[0,328],[0,328],[0,328],[0,328],[0,328],[0,329],[0,329],[0,329],[0,329],[0,329],[0,330],[0,330],[0,330],[0,330],[0,330],[0,331],[0,331],[0,331],[0,331],[0,331],[0,332],[0,332],[0,332],[0,332],[0,332],[0,333],[0,333],[0,333],[0,333],[0,333],[0,334],[0,334],[0,334],[0,334],[0,334],[0,335],[0,335],[0,335],[0,335],[0,335],[0,336],[0,336],[0,336],[0,336],[0,336],[0,337],[0,337],[0,337],[0,337],[0,337],[0,338],[0,338],[0,338],[0,338],[0,338],[0,339],[0,339],[0,339],[0,339],[0,339],[0,340],[0,340],[0,340],[0,340],[0,340],[0,341],[0,341],[0,341],[0,341],[0,341],[0,342],[0,342],[0,342],[0,342],[0,342],[0,343],[0,343],[0,343],[0,343],[0,343],[0,344],[0,344],[0,344],[0,344],[0,344],[0,345],[0,345],[0,345],[0,345],[0,345],[0,346],[0,346],[0,346],[0,346],[0,346],[0,347],[0,347],[0,347],[0,347],[0,347],[0,348],[0,348],[0,348],[0,348],[0,348],[0,349],[0,349],[0,349],[0,349],[0,349],[0,350],[0,350],[0,350],[0,350],[0,350],[0,351],[0,351],[0,351],[0,351],[0,351],[0,352],[0,352],[0,352],[0,352],[0,352],[0,353],[0,353],[0,353],[0,353],[0,353],[0,354],[0,354],[0,354],[0,354],[0,354],[0,355],[0,355],[0,355],[0,355],[0,355],[0,356],[0,356],[0,356],[0,356],[0,356],[0,357],[0,357],[0,357],[0,357],[0,357],[0,358],[0,358],[0,358],[0,358],[0,358],[0,359],[0,359],[0,359],[0,359],[0,359],[0,360],[0,360],[0,360],[0,360],[0,360],[0,361],[0,361],[0,361],[0,361],[0,361],[0,362],[0,362],[0,362],[0,362],[0,362],[0,363],[0,363],[0,363],[0,363],[0,363],[0,364],[0,364],[0,364],[0,364],[0,364],[0,365],[0,365],[0,365],[0,365],[0,365],[0,366],[0,366],[0,366],[0,366],[0,366],[0,367],[0,367],[0,367],[0,367],[0,367],[0,368],[0,368],[0,368],[0,368],[0,368],[0,369],[0,369],[0,369],[0,369],[0,369],[0,370],[0,370],[0,370],[0,370],[0,370],[0,371],[0,371],[0,371],[0,371],[0,371],[0,372],[0,372],[0,372],[0,372],[0,372],[0,373],[0,373],[0,373],[0,373],[0,373],[0,374],[0,374],[0,374],[0,374],[0,374],[0,375],[0,375],[0,375],[0,375],[0,375],[0,376],[0,376],[0,376],[0,376],[0,376],[0,377],[0,377],[0,377],[0,377],[0,377],[0,378],[0,378],[0,378],[0,378],[0,378],[0,379],[0,379],[0,379],[0,379],[0,379],[0,380],[0,380],[0,380],[0,380],[0,380],[0,381],[0,381],[0,381],[0,381],[0,381],[0,382],[0,382],[0,382],[0,382],[0,382],[0,383],[0,383],[0,383],[0,383],[0,383],[0,384],[0,384],[0,384],[0,384],[0,384],[0,385],[0,385],[0,385],[0,385],[0,385],[0,386],[0,386],[0,386],[0,386],[0,386],[0,387],[0,387],[0,387],[0,387],[0,387],[0,388],[0,388],[0,388],[0,388],[0,388],[0,389],[0,389],[0,389],[0,389],[0,389],[0,390],[0,390],[0,390],[0,390],[0,390],[0,391],[0,391],[0,391],[0,391],[0,391],[0,392],[0,392],[0,392],[0,392],[0,392],[0,393],[0,393],[0,393],[0,393],[0,393],[0,394],[0,394],[0,394],[0,394],[0,394],[0,395],[0,395],[0,395],[0,395],[0,395],[0,396],[0,396],[0,396],[0,396],[0,396],[0,397],[0,397],[0,397],[0,397],[0,397],[0,398],[0,398],[0,398],[0,398],[0,398],[0,399],[0,399],[0,399],[0,399],[0,399],[0,400],[0,400],[0,400],[0,400],[0,400],[0,401],[0,401],[0,401],[0,401],[0,401],[0,402],[0,402],[0,402],[0,402],[0,402],[0,403],[0,403],[0,403],[0,403],[0,403],[0,404],[0,404],[0,404],[0,404],[0,404],[0,405],[0,405],[0,405],[0,405],[0,405],[0,406],[0,406],[0,406],[0,406],[0,406],[0,407],[0,407],[0,407],[0,407],[0,407],[0,408],[0,408],[0,408],[0,408],[0,408],[0,409],[0,409],[0,409],[0,409],[0,409],[0,410],[0,410],[0,410],[0,410],[0,410],[0,411],[0,411],[0,411],[0,411],[0,411],[0,412],[0,412],[0,412],[0,412],[0,412],[0,413],[0,413],[0,413],[0,413],[0,413],[0,414],[0,414],[0,414],[0,414],[0,414],[0,415],[0,415],[0,415],[0,415],[0,415],[0,416],[0,416],[0,416],[0,416],[0,416],[0,417],[0,417],[0,417],[0,417],[0,417],[0,418],[0,418],[0,418],[0,418],[0,418],[0,419],[0,419],[0,419],[0,419],[0,419],[0,420],[0,420],[0,420],[0,420],[0,420],[0,421],[0,421],[0,421],[0,421],[0,421],[0,422],[0,422],[0,422],[0,422],[0,422],[0,423],[0,423],[0,423],[0,423],[0,423],[0,424],[0,424],[0,424],[0,424],[0,424],[0,425],[0,425],[0,425],[0,425],[0,425],[0,426],[0,426],[0,426],[0,426],[0,426],[0,427],[0,427],[0,427],[0,427],[0,427],[0,428],[0,428],[0,428],[0,428],[0,428],[0,429],[0,429],[0,429],[0,429],[0,429],[0,430],[0,430],[0,430],[0,430],[0,430],[0,431],[0,431],[0,431],[0,431],[0,431],[0,432],[0,432],[0,432],[0,432],[0,432],[0,433],[0,433],[0,433],[0,433],[0,433],[0,434],[0,434],[0,434],[0,434],[0,434],[0,435],[0,435],[0,435],[0,435],[0,435],[0,436],[0,436],[0,436],[0,436],[0,436],[0,437],[0,437],[0,437],[0,437],[0,437],[0,438],[0,438],[0,438],[0,438],[0,438],[0,439],[0,439],[0,439],[0,439],[0,439],[0,440],[0,440],[0,440],[0,440],[0,440],[0,441],[0,441],[0,441],[0,441],[0,441],[0,442],[0,442],[0,442],[0,442],[0,442],[0,443],[0,443],[0,443],[0,443],[0,443],[0,444],[0,444],[0,444],[0,444],[0,444],[0,445],[0,445],[0,445],[0,445],[0,445],[0,446],[0,446],[0,446],[0,446],[0,446],[0,447],[0,447],[0,447],[0,447],[0,447],[0,448],[0,448],[0,448],[0,448],[0,448],[0,449],[0,449],[0,449],[0,449],[0,449],[0,450],[0,450],[0,450],[0,450],[0,450],[0,451],[0,451],[0,451],[0,451],[0,451],[0,452],[0,452],[0,452],[0,452],[0,452],[0,453],[0,453],[0,453],[0,453],[0,453],[0,454],[0,454],[0,454],[0,454],[0,454],[0,455],[0,455],[0,455],[0,455],[0,455],[0,456],[0,456],[0,456],[0,456],[0,456],[0,457],[0,457],[0,457],[0,457],[0,457],[0,458],[0,458],[0,458],[0,458],[0,458],[0,459],[0,459],[0,459],[0,459],[0,459],[0,460],[0,460],[0,460],[0,460],[0,460],[0,461],[0,461],[0,461],[0,461],[0,461],[0,462],[0,462],[0,462],[0,462],[0,462],[0,463],[0,463],[0,463],[0,463],[0,463],[0,464],[0,464],[0,464],[0,464],[0,464],[0,465],[0,465],[0,465],[0,465],[0,465],[0,466],[0,466],[0,466],[0,466],[0,466],[0,467],[0,467],[0,467],[0,467],[0,467],[0,468],[0,468],[0,468],[0,468],[0,468],[0,469],[0,469],[0,469],[0,469],[0,469],[0,470],[0,470],[0,470],[0,470],[0,470],[0,471],[0,471],[0,471],[0,471],[0,471],[0,472],[0,472],[0,472],[0,472],[0,472],[0,473],[0,473],[0,473],[0,473],[0,473],[0,474],[0,474],[0,474],[0,474],[0,474],[0,475],[0,475],[0,475],[0,475],[0,475],[0,476],[0,476],[0,476],[0,476],[0,476],[0,477],[0,477],[0,477],[0,477],[0,477],[0,478],[0,478],[0,478],[0,478],[0,478],[0,479],[0,479],[0,479],[0,479],[0,479],[0,480],[0,480],[0,480],[0,480],[0,480],[0,481],[0,481],[0,481],[0,481],[0,481],[0,482],[0,482],[0,482],[0,482],[0,482],[0,483],[0,483],[0,483],[0,483],[0,483],[0,484],[0,484],[0,484],[0,484],[0,484],[0,485],[0,485],[0,485],[0,485],[0,485],[0,486],[0,486],[0,486],[0,486],[0,486],[0,487],[0,487],[0,487],[0,487],[0,487],[0,488],[0,488],[0,488],[0,488],[0,488],[0,489],[0,489],[0,489],[0,489],[0,489],[0,490],[0,490],[0,490],[0,490],[0,490],[0,491],[0,491],[0,491],[0,491],[0,491],[0,492],[0,492],[0,492],[0,492],[0,492],[0,493],[0,493],[0,493],[0,493],[0,493],[0,494],[0,494],[0,494],[0,494],[0,494],[0,495],[0,495],[0,495],[0,495],[0,495],[0,496],[0,496],[0,496],[0,496],[0,496],[0,497],[0,497],[0,497],[0,497],[0,497],[0,498],[0,498],[0,498],[0,498],[0,498],[0,499],[0,499],[0,499],[0,499],[0,499],[0,500],[0,500],[0,500],[0,500],[0,500],[1,2],[1,2],[1,2],[1,2],[1,2],[1,3],[1,3],[1,3],[1,3],[1,3],[1,4],[1,4],[1,4],[1,4],[1,4],[1,5],[1,5],[1,5],[1,5],[1,5],[1,6],[1,6],[1,6],[1,6],[1,6],[1,7],[1,7],[1,7],[1,7],[1,7],[1,8],[1,8],[1,8],[1,8],[1,8],[1,9],[1,9],[1,9],[1,9],[1,9],[1,10],[1,10],[1,10],[1,10],[1,10],[1,11],[1,11],[1,11],[1,11],[1,11],[1,12],[1,12],[1,12],[1,12],[1,12],[1,13],[1,13],[1,13],[1,13],[1,13],[1,14],[1,14],[1,14],[1,14],[1,14],[1,15],[1,15],[1,15],[1,15],[1,15],[1,16],[1,16],[1,16],[1,16],[1,16],[1,17],[1,17],[1,17],[1,17],[1,17],[1,18],[1,18],[1,18],[1,18],[1,18],[1,19],[1,19],[1,19],[1,19],[1,19],[1,20],[1,20],[1,20],[1,20],[1,20],[1,21],[1,21],[1,21],[1,21],[1,21],[1,22],[1,22],[1,22],[1,22],[1,22],[1,23],[1,23],[1,23],[1,23],[1,23],[1,24],[1,24],[1,24],[1,24],[1,24],[1,25],[1,25],[1,25],[1,25],[1,25],[1,26],[1,26],[1,26],[1,26],[1,26],[1,27],[1,27],[1,27],[1,27],[1,27],[1,28],[1,28],[1,28],[1,28],[1,28],[1,29],[1,29],[1,29],[1,29],[1,29],[1,30],[1,30],[1,30],[1,30],[1,30],[1,31],[1,31],[1,31],[1,31],[1,31],[1,32],[1,32],[1,32],[1,32],[1,32],[1,33],[1,33],[1,33],[1,33],[1,33],[1,34],[1,34],[1,34],[1,34],[1,34],[1,35],[1,35],[1,35],[1,35],[1,35],[1,36],[1,36],[1,36],[1,36],[1,36],[1,37],[1,37],[1,37],[1,37],[1,37],[1,38],[1,38],[1,38],[1,38],[1,38],[1,39],[1,39],[1,39],[1,39],[1,39],[1,40],[1,40],[1,40],[1,40],[1,40],[1,41],[1,41],[1,41],[1,41],[1,41],[1,42],[1,42],[1,42],[1,42],[1,42],[1,43],[1,43],[1,43],[1,43],[1,43],[1,44],[1,44],[1,44],[1,44],[1,44],[1,45],[1,45],[1,45],[1,45],[1,45],[1,46],[1,46],[1,46],[1,46],[1,46],[1,47],[1,47],[1,47],[1,47],[1,47],[1,48],[1,48],[1,48],[1,48],[1,48],[1,49],[1,49],[1,49],[1,49],[1,49],[1,50],[1,50],[1,50],[1,50],[1,50],[1,51],[1,51],[1,51],[1,51],[1,51],[1,52],[1,52],[1,52],[1,52],[1,52],[1,53],[1,53],[1,53],[1,53],[1,53],[1,54],[1,54],[1,54],[1,54],[1,54],[1,55],[1,55],[1,55],[1,55],[1,55],[1,56],[1,56],[1,56],[1,56],[1,56],[1,57],[1,57],[1,57],[1,57],[1,57],[1,58],[1,58],[1,58],[1,58],[1,58],[1,59],[1,59],[1,59],[1,59],[1,59],[1,60],[1,60],[1,60],[1,60],[1,60],[1,61],[1,61],[1,61],[1,61],[1,61],[1,62],[1,62],[1,62],[1,62],[1,62],[1,63],[1,63],[1,63],[1,63],[1,63],[1,64],[1,64],[1,64],[1,64],[1,64],[1,65],[1,65],[1,65],[1,65],[1,65],[1,66],[1,66],[1,66],[1,66],[1,66],[1,67],[1,67],[1,67],[1,67],[1,67],[1,68],[1,68],[1,68],[1,68],[1,68],[1,69],[1,69],[1,69],[1,69],[1,69],[1,70],[1,70],[1,70],[1,70],[1,70],[1,71],[1,71],[1,71],[1,71],[1,71],[1,72],[1,72],[1,72],[1,72],[1,72],[1,73],[1,73],[1,73],[1,73],[1,73],[1,74],[1,74],[1,74],[1,74],[1,74],[1,75],[1,75],[1,75],[1,75],[1,75],[1,76],[1,76],[1,76],[1,76],[1,76],[1,77],[1,77],[1,77],[1,77],[1,77],[1,78],[1,78],[1,78],[1,78],[1,78],[1,79],[1,79],[1,79],[1,79],[1,79],[1,80],[1,80],[1,80],[1,80],[1,80],[1,81],[1,81],[1,81],[1,81],[1,81],[1,82],[1,82],[1,82],[1,82],[1,82],[1,83],[1,83],[1,83],[1,83],[1,83],[1,84],[1,84],[1,84],[1,84],[1,84],[1,85],[1,85],[1,85],[1,85],[1,85],[1,86],[1,86],[1,86],[1,86],[1,86],[1,87],[1,87],[1,87],[1,87],[1,87],[1,88],[1,88],[1,88],[1,88],[1,88],[1,89],[1,89],[1,89],[1,89],[1,89],[1,90],[1,90],[1,90],[1,90],[1,90],[1,91],[1,91],[1,91],[1,91],[1,91],[1,92],[1,92],[1,92],[1,92],[1,92],[1,93],[1,93],[1,93],[1,93],[1,93],[1,94],[1,94],[1,94],[1,94],[1,94],[1,95],[1,95],[1,95],[1,95],[1,95],[1,96],[1,96],[1,96],[1,96],[1,96],[1,97],[1,97],[1,97],[1,97],[1,97],[1,98],[1,98],[1,98],[1,98],[1,98],[1,99],[1,99],[1,99],[1,99],[1,99],[1,100],[1,100],[1,100],[1,100],[1,100],[1,101],[1,101],[1,101],[1,101],[1,101],[1,102],[1,102],[1,102],[1,102],[1,102],[1,103],[1,103],[1,103],[1,103],[1,103],[1,104],[1,104],[1,104],[1,104],[1,104],[1,105],[1,105],[1,105],[1,105],[1,105],[1,106],[1,106],[1,106],[1,106],[1,106],[1,107],[1,107],[1,107],[1,107],[1,107],[1,108],[1,108],[1,108],[1,108],[1,108],[1,109],[1,109],[1,109],[1,109],[1,109],[1,110],[1,110],[1,110],[1,110],[1,110],[1,111],[1,111],[1,111],[1,111],[1,111],[1,112],[1,112],[1,112],[1,112],[1,112],[1,113],[1,113],[1,113],[1,113],[1,113],[1,114],[1,114],[1,114],[1,114],[1,114],[1,115],[1,115],[1,115],[1,115],[1,115],[1,116],[1,116],[1,116],[1,116],[1,116],[1,117],[1,117],[1,117],[1,117],[1,117],[1,118],[1,118],[1,118],[1,118],[1,118],[1,119],[1,119],[1,119],[1,119],[1,119],[1,120],[1,120],[1,120],[1,120],[1,120],[1,121],[1,121],[1,121],[1,121],[1,121],[1,122],[1,122],[1,122],[1,122],[1,122],[1,123],[1,123],[1,123],[1,123],[1,123],[1,124],[1,124],[1,124],[1,124],[1,124],[1,125],[1,125],[1,125],[1,125],[1,125],[1,126],[1,126],[1,126],[1,126],[1,126],[1,127],[1,127],[1,127],[1,127],[1,127],[1,128],[1,128],[1,128],[1,128],[1,128],[1,129],[1,129],[1,129],[1,129],[1,129],[1,130],[1,130],[1,130],[1,130],[1,130],[1,131],[1,131],[1,131],[1,131],[1,131],[1,132],[1,132],[1,132],[1,132],[1,132],[1,133],[1,133],[1,133],[1,133],[1,133],[1,134],[1,134],[1,134],[1,134],[1,134],[1,135],[1,135],[1,135],[1,135],[1,135],[1,136],[1,136],[1,136],[1,136],[1,136],[1,137],[1,137],[1,137],[1,137],[1,137],[1,138],[1,138],[1,138],[1,138],[1,138],[1,139],[1,139],[1,139],[1,139],[1,139],[1,140],[1,140],[1,140],[1,140],[1,140],[1,141],[1,141],[1,141],[1,141],[1,141],[1,142],[1,142],[1,142],[1,142],[1,142],[1,143],[1,143],[1,143],[1,143],[1,143],[1,144],[1,144],[1,144],[1,144],[1,144],[1,145],[1,145],[1,145],[1,145],[1,145],[1,146],[1,146],[1,146],[1,146],[1,146],[1,147],[1,147],[1,147],[1,147],[1,147],[1,148],[1,148],[1,148],[1,148],[1,148],[1,149],[1,149],[1,149],[1,149],[1,149],[1,150],[1,150],[1,150],[1,150],[1,150],[1,151],[1,151],[1,151],[1,151],[1,151],[1,152],[1,152],[1,152],[1,152],[1,152],[1,153],[1,153],[1,153],[1,153],[1,153],[1,154],[1,154],[1,154],[1,154],[1,154],[1,155],[1,155],[1,155],[1,155],[1,155],[1,156],[1,156],[1,156],[1,156],[1,156],[1,157],[1,157],[1,157],[1,157],[1,157],[1,158],[1,158],[1,158],[1,158],[1,158],[1,159],[1,159],[1,159],[1,159],[1,159],[1,160],[1,160],[1,160],[1,160],[1,160],[1,161],[1,161],[1,161],[1,161],[1,161],[1,162],[1,162],[1,162],[1,162],[1,162],[1,163],[1,163],[1,163],[1,163],[1,163],[1,164],[1,164],[1,164],[1,164],[1,164],[1,165],[1,165],[1,165],[1,165],[1,165],[1,166],[1,166],[1,166],[1,166],[1,166],[1,167],[1,167],[1,167],[1,167],[1,167],[1,168],[1,168],[1,168],[1,168],[1,168],[1,169],[1,169],[1,169],[1,169],[1,169],[1,170],[1,170],[1,170],[1,170],[1,170],[1,171],[1,171],[1,171],[1,171],[1,171],[1,172],[1,172],[1,172],[1,172],[1,172],[1,173],[1,173],[1,173],[1,173],[1,173],[1,174],[1,174],[1,174],[1,174],[1,174],[1,175],[1,175],[1,175],[1,175],[1,175],[1,176],[1,176],[1,176],[1,176],[1,176],[1,177],[1,177],[1,177],[1,177],[1,177],[1,178],[1,178],[1,178],[1,178],[1,178],[1,179],[1,179],[1,179],[1,179],[1,179],[1,180],[1,180],[1,180],[1,180],[1,180],[1,181],[1,181],[1,181],[1,181],[1,181],[1,182],[1,182],[1,182],[1,182],[1,182],[1,183],[1,183],[1,183],[1,183],[1,183],[1,184],[1,184],[1,184],[1,184],[1,184],[1,185],[1,185],[1,185],[1,185],[1,185],[1,186],[1,186],[1,186],[1,186],[1,186],[1,187],[1,187],[1,187],[1,187],[1,187],[1,188],[1,188],[1,188],[1,188],[1,188],[1,189],[1,189],[1,189],[1,189],[1,189],[1,190],[1,190],[1,190],[1,190],[1,190],[1,191],[1,191],[1,191],[1,191],[1,191],[1,192],[1,192],[1,192],[1,192],[1,192],[1,193],[1,193],[1,193],[1,193],[1,193],[1,194],[1,194],[1,194],[1,194],[1,194],[1,195],[1,195],[1,195],[1,195],[1,195],[1,196],[1,196],[1,196],[1,196],[1,196],[1,197],[1,197],[1,197],[1,197],[1,197],[1,198],[1,198],[1,198],[1,198],[1,198],[1,199],[1,199],[1,199],[1,199],[1,199],[1,200],[1,200],[1,200],[1,200],[1,200],[1,201],[1,201],[1,201],[1,201],[1,201],[1,202],[1,202],[1,202],[1,202],[1,202],[1,203],[1,203],[1,203],[1,203],[1,203],[1,204],[1,204],[1,204],[1,204],[1,204],[1,205],[1,205],[1,205],[1,205],[1,205],[1,206],[1,206],[1,206],[1,206],[1,206],[1,207],[1,207],[1,207],[1,207],[1,207],[1,208],[1,208],[1,208],[1,208],[1,208],[1,209],[1,209],[1,209],[1,209],[1,209],[1,210],[1,210],[1,210],[1,210],[1,210],[1,211],[1,211],[1,211],[1,211],[1,211],[1,212],[1,212],[1,212],[1,212],[1,212],[1,213],[1,213],[1,213],[1,213],[1,213],[1,214],[1,214],[1,214],[1,214],[1,214],[1,215],[1,215],[1,215],[1,215],[1,215],[1,216],[1,216],[1,216],[1,216],[1,216],[1,217],[1,217],[1,217],[1,217],[1,217],[1,218],[1,218],[1,218],[1,218],[1,218],[1,219],[1,219],[1,219],[1,219],[1,219],[1,220],[1,220],[1,220],[1,220],[1,220],[1,221],[1,221],[1,221],[1,221],[1,221],[1,222],[1,222],[1,222],[1,222],[1,222],[1,223],[1,223],[1,223],[1,223],[1,223],[1,224],[1,224],[1,224],[1,224],[1,224],[1,225],[1,225],[1,225],[1,225],[1,225],[1,226],[1,226],[1,226],[1,226],[1,226],[1,227],[1,227],[1,227],[1,227],[1,227],[1,228],[1,228],[1,228],[1,228],[1,228],[1,229],[1,229],[1,229],[1,229],[1,229],[1,230],[1,230],[1,230],[1,230],[1,230],[1,231],[1,231],[1,231],[1,231],[1,231],[1,232],[1,232],[1,232],[1,232],[1,232],[1,233],[1,233],[1,233],[1,233],[1,233],[1,234],[1,234],[1,234],[1,234],[1,234],[1,235],[1,235],[1,235],[1,235],[1,235],[1,236],[1,236],[1,236],[1,236],[1,236],[1,237],[1,237],[1,237],[1,237],[1,237],[1,238],[1,238],[1,238],[1,238],[1,238],[1,239],[1,239],[1,239],[1,239],[1,239],[1,240],[1,240],[1,240],[1,240],[1,240],[1,241],[1,241],[1,241],[1,241],[1,241],[1,242],[1,242],[1,242],[1,242],[1,242],[1,243],[1,243],[1,243],[1,243],[1,243],[1,244],[1,244],[1,244],[1,244],[1,244],[1,245],[1,245],[1,245],[1,245],[1,245],[1,246],[1,246],[1,246],[1,246],[1,246],[1,247],[1,247],[1,247],[1,247],[1,247],[1,248],[1,248],[1,248],[1,248],[1,248],[1,249],[1,249],[1,249],[1,249],[1,249],[1,250],[1,250],[1,250],[1,250],[1,250],[1,251],[1,251],[1,251],[1,251],[1,251],[1,252],[1,252],[1,252],[1,252],[1,252],[1,253],[1,253],[1,253],[1,253],[1,253],[1,254],[1,254],[1,254],[1,254],[1,254],[1,255],[1,255],[1,255],[1,255],[1,255],[1,256],[1,256],[1,256],[1,256],[1,256],[1,257],[1,257],[1,257],[1,257],[1,257],[1,258],[1,258],[1,258],[1,258],[1,258],[1,259],[1,259],[1,259],[1,259],[1,259],[1,260],[1,260],[1,260],[1,260],[1,260],[1,261],[1,261],[1,261],[1,261],[1,261],[1,262],[1,262],[1,262],[1,262],[1,262],[1,263],[1,263],[1,263],[1,263],[1,263],[1,264],[1,264],[1,264],[1,264],[1,264],[1,265],[1,265],[1,265],[1,265],[1,265],[1,266],[1,266],[1,266],[1,266],[1,266],[1,267],[1,267],[1,267],[1,267],[1,267],[1,268],[1,268],[1,268],[1,268],[1,268],[1,269],[1,269],[1,269],[1,269],[1,269],[1,270],[1,270],[1,270],[1,270],[1,270],[1,271],[1,271],[1,271],[1,271],[1,271],[1,272],[1,272],[1,272],[1,272],[1,272],[1,273],[1,273],[1,273],[1,273],[1,273],[1,274],[1,274],[1,274],[1,274],[1,274],[1,275],[1,275],[1,275],[1,275],[1,275],[1,276],[1,276],[1,276],[1,276],[1,276],[1,277],[1,277],[1,277],[1,277],[1,277],[1,278],[1,278],[1,278],[1,278],[1,278],[1,279],[1,279],[1,279],[1,279],[1,279],[1,280],[1,280],[1,280],[1,280],[1,280],[1,281],[1,281],[1,281],[1,281],[1,281],[1,282],[1,282],[1,282],[1,282],[1,282],[1,283],[1,283],[1,283],[1,283],[1,283],[1,284],[1,284],[1,284],[1,284],[1,284],[1,285],[1,285],[1,285],[1,285],[1,285],[1,286],[1,286],[1,286],[1,286],[1,286],[1,287],[1,287],[1,287],[1,287],[1,287],[1,288],[1,288],[1,288],[1,288],[1,288],[1,289],[1,289],[1,289],[1,289],[1,289],[1,290],[1,290],[1,290],[1,290],[1,290],[1,291],[1,291],[1,291],[1,291],[1,291],[1,292],[1,292],[1,292],[1,292],[1,292],[1,293],[1,293],[1,293],[1,293],[1,293],[1,294],[1,294],[1,294],[1,294],[1,294],[1,295],[1,295],[1,295],[1,295],[1,295],[1,296],[1,296],[1,296],[1,296],[1,296],[1,297],[1,297],[1,297],[1,297],[1,297],[1,298],[1,298],[1,298],[1,298],[1,298],[1,299],[1,299],[1,299],[1,299],[1,299],[1,300],[1,300],[1,300],[1,300],[1,300],[1,301],[1,301],[1,301],[1,301],[1,301],[1,302],[1,302],[1,302],[1,302],[1,302],[1,303],[1,303],[1,303],[1,303],[1,303],[1,304],[1,304],[1,304],[1,304],[1,304],[1,305],[1,305],[1,305],[1,305],[1,305],[1,306],[1,306],[1,306],[1,306],[1,306],[1,307],[1,307],[1,307],[1,307],[1,307],[1,308],[1,308],[1,308],[1,308],[1,308],[1,309],[1,309],[1,309],[1,309],[1,309],[1,310],[1,310],[1,310],[1,310],[1,310],[1,311],[1,311],[1,311],[1,311],[1,311],[1,312],[1,312],[1,312],[1,312],[1,312],[1,313],[1,313],[1,313],[1,313],[1,313],[1,314],[1,314],[1,314],[1,314],[1,314],[1,315],[1,315],[1,315],[1,315],[1,315],[1,316],[1,316],[1,316],[1,316],[1,316],[1,317],[1,317],[1,317],[1,317],[1,317],[1,318],[1,318],[1,318],[1,318],[1,318],[1,319],[1,319],[1,319],[1,319],[1,319],[1,320],[1,320],[1,320],[1,320],[1,320],[1,321],[1,321],[1,321],[1,321],[1,321],[1,322],[1,322],[1,322],[1,322],[1,322],[1,323],[1,323],[1,323],[1,323],[1,323],[1,324],[1,324],[1,324],[1,324],[1,324],[1,325],[1,325],[1,325],[1,325],[1,325],[1,326],[1,326],[1,326],[1,326],[1,326],[1,327],[1,327],[1,327],[1,327],[1,327],[1,328],[1,328],[1,328],[1,328],[1,328],[1,329],[1,329],[1,329],[1,329],[1,329],[1,330],[1,330],[1,330],[1,330],[1,330],[1,331],[1,331],[1,331],[1,331],[1,331],[1,332],[1,332],[1,332],[1,332],[1,332],[1,333],[1,333],[1,333],[1,333],[1,333],[1,334],[1,334],[1,334],[1,334],[1,334],[1,335],[1,335],[1,335],[1,335],[1,335],[1,336],[1,336],[1,336],[1,336],[1,336],[1,337],[1,337],[1,337],[1,337],[1,337],[1,338],[1,338],[1,338],[1,338],[1,338],[1,339],[1,339],[1,339],[1,339],[1,339],[1,340],[1,340],[1,340],[1,340],[1,340],[1,341],[1,341],[1,341],[1,341],[1,341],[1,342],[1,342],[1,342],[1,342],[1,342],[1,343],[1,343],[1,343],[1,343],[1,343],[1,344],[1,344],[1,344],[1,344],[1,344],[1,345],[1,345],[1,345],[1,345],[1,345],[1,346],[1,346],[1,346],[1,346],[1,346],[1,347],[1,347],[1,347],[1,347],[1,347],[1,348],[1,348],[1,348],[1,348],[1,348],[1,349],[1,349],[1,349],[1,349],[1,349],[1,350],[1,350],[1,350],[1,350],[1,350],[1,351],[1,351],[1,351],[1,351],[1,351],[1,352],[1,352],[1,352],[1,352],[1,352],[1,353],[1,353],[1,353],[1,353],[1,353],[1,354],[1,354],[1,354],[1,354],[1,354],[1,355],[1,355],[1,355],[1,355],[1,355],[1,356],[1,356],[1,356],[1,356],[1,356],[1,357],[1,357],[1,357],[1,357],[1,357],[1,358],[1,358],[1,358],[1,358],[1,358],[1,359],[1,359],[1,359],[1,359],[1,359],[1,360],[1,360],[1,360],[1,360],[1,360],[1,361],[1,361],[1,361],[1,361],[1,361],[1,362],[1,362],[1,362],[1,362],[1,362],[1,363],[1,363],[1,363],[1,363],[1,363],[1,364],[1,364],[1,364],[1,364],[1,364],[1,365],[1,365],[1,365],[1,365],[1,365],[1,366],[1,366],[1,366],[1,366],[1,366],[1,367],[1,367],[1,367],[1,367],[1,367],[1,368],[1,368],[1,368],[1,368],[1,368],[1,369],[1,369],[1,369],[1,369],[1,369],[1,370],[1,370],[1,370],[1,370],[1,370],[1,371],[1,371],[1,371],[1,371],[1,371],[1,372],[1,372],[1,372],[1,372],[1,372],[1,373],[1,373],[1,373],[1,373],[1,373],[1,374],[1,374],[1,374],[1,374],[1,374],[1,375],[1,375],[1,375],[1,375],[1,375],[1,376],[1,376],[1,376],[1,376],[1,376],[1,377],[1,377],[1,377],[1,377],[1,377],[1,378],[1,378],[1,378],[1,378],[1,378],[1,379],[1,379],[1,379],[1,379],[1,379],[1,380],[1,380],[1,380],[1,380],[1,380],[1,381],[1,381],[1,381],[1,381],[1,381],[1,382],[1,382],[1,382],[1,382],[1,382],[1,383],[1,383],[1,383],[1,383],[1,383],[1,384],[1,384],[1,384],[1,384],[1,384],[1,385],[1,385],[1,385],[1,385],[1,385],[1,386],[1,386],[1,386],[1,386],[1,386],[1,387],[1,387],[1,387],[1,387],[1,387],[1,388],[1,388],[1,388],[1,388],[1,388],[1,389],[1,389],[1,389],[1,389],[1,389],[1,390],[1,390],[1,390],[1,390],[1,390],[1,391],[1,391],[1,391],[1,391],[1,391],[1,392],[1,392],[1,392],[1,392],[1,392],[1,393],[1,393],[1,393],[1,393],[1,393],[1,394],[1,394],[1,394],[1,394],[1,394],[1,395],[1,395],[1,395],[1,395],[1,395],[1,396],[1,396],[1,396],[1,396],[1,396],[1,397],[1,397],[1,397],[1,397],[1,397],[1,398],[1,398],[1,398],[1,398],[1,398],[1,399],[1,399],[1,399],[1,399],[1,399],[1,400],[1,400],[1,400],[1,400],[1,400],[1,401],[1,401],[1,401],[1,401],[1,401],[1,402],[1,402],[1,402],[1,402],[1,402],[1,403],[1,403],[1,403],[1,403],[1,403],[1,404],[1,404],[1,404],[1,404],[1,404],[1,405],[1,405],[1,405],[1,405],[1,405],[1,406],[1,406],[1,406],[1,406],[1,406],[1,407],[1,407],[1,407],[1,407],[1,407],[1,408],[1,408],[1,408],[1,408],[1,408],[1,409],[1,409],[1,409],[1,409],[1,409],[1,410],[1,410],[1,410],[1,410],[1,410],[1,411],[1,411],[1,411],[1,411],[1,411],[1,412],[1,412],[1,412],[1,412],[1,412],[1,413],[1,413],[1,413],[1,413],[1,413],[1,414],[1,414],[1,414],[1,414],[1,414],[1,415],[1,415],[1,415],[1,415],[1,415],[1,416],[1,416],[1,416],[1,416],[1,416],[1,417],[1,417],[1,417],[1,417],[1,417],[1,418],[1,418],[1,418],[1,418],[1,418],[1,419],[1,419],[1,419],[1,419],[1,419],[1,420],[1,420],[1,420],[1,420],[1,420],[1,421],[1,421],[1,421],[1,421],[1,421],[1,422],[1,422],[1,422],[1,422],[1,422],[1,423],[1,423],[1,423],[1,423],[1,423],[1,424],[1,424],[1,424],[1,424],[1,424],[1,425],[1,425],[1,425],[1,425],[1,425],[1,426],[1,426],[1,426],[1,426],[1,426],[1,427],[1,427],[1,427],[1,427],[1,427],[1,428],[1,428],[1,428],[1,428],[1,428],[1,429],[1,429],[1,429],[1,429],[1,429],[1,430],[1,430],[1,430],[1,430],[1,430],[1,431],[1,431],[1,431],[1,431],[1,431],[1,432],[1,432],[1,432],[1,432],[1,432],[1,433],[1,433],[1,433],[1,433],[1,433],[1,434],[1,434],[1,434],[1,434],[1,434],[1,435],[1,435],[1,435],[1,435],[1,435],[1,436],[1,436],[1,436],[1,436],[1,436],[1,437],[1,437],[1,437],[1,437],[1,437],[1,438],[1,438],[1,438],[1,438],[1,438],[1,439],[1,439],[1,439],[1,439],[1,439],[1,440],[1,440],[1,440],[1,440],[1,440],[1,441],[1,441],[1,441],[1,441],[1,441],[1,442],[1,442],[1,442],[1,442],[1,442],[1,443],[1,443],[1,443],[1,443],[1,443],[1,444],[1,444],[1,444],[1,444],[1,444],[1,445],[1,445],[1,445],[1,445],[1,445],[1,446],[1,446],[1,446],[1,446],[1,446],[1,447],[1,447],[1,447],[1,447],[1,447],[1,448],[1,448],[1,448],[1,448],[1,448],[1,449],[1,449],[1,449],[1,449],[1,449],[1,450],[1,450],[1,450],[1,450],[1,450],[1,451],[1,451],[1,451],[1,451],[1,451],[1,452],[1,452],[1,452],[1,452],[1,452],[1,453],[1,453],[1,453],[1,453],[1,453],[1,454],[1,454],[1,454],[1,454],[1,454],[1,455],[1,455],[1,455],[1,455],[1,455],[1,456],[1,456],[1,456],[1,456],[1,456],[1,457],[1,457],[1,457],[1,457],[1,457],[1,458],[1,458],[1,458],[1,458],[1,458],[1,459],[1,459],[1,459],[1,459],[1,459],[1,460],[1,460],[1,460],[1,460],[1,460],[1,461],[1,461],[1,461],[1,461],[1,461],[1,462],[1,462],[1,462],[1,462],[1,462],[1,463],[1,463],[1,463],[1,463],[1,463],[1,464],[1,464],[1,464],[1,464],[1,464],[1,465],[1,465],[1,465],[1,465],[1,465],[1,466],[1,466],[1,466],[1,466],[1,466],[1,467],[1,467],[1,467],[1,467],[1,467],[1,468],[1,468],[1,468],[1,468],[1,468],[1,469],[1,469],[1,469],[1,469],[1,469],[1,470],[1,470],[1,470],[1,470],[1,470],[1,471],[1,471],[1,471],[1,471],[1,471],[1,472],[1,472],[1,472],[1,472],[1,472],[1,473],[1,473],[1,473],[1,473],[1,473],[1,474],[1,474],[1,474],[1,474],[1,474],[1,475],[1,475],[1,475],[1,475],[1,475],[1,476],[1,476],[1,476],[1,476],[1,476],[1,477],[1,477],[1,477],[1,477],[1,477],[1,478],[1,478],[1,478],[1,478],[1,478],[1,479],[1,479],[1,479],[1,479],[1,479],[1,480],[1,480],[1,480],[1,480],[1,480],[1,481],[1,481],[1,481],[1,481],[1,481],[1,482],[1,482],[1,482],[1,482],[1,482],[1,483],[1,483],[1,483],[1,483],[1,483],[1,484],[1,484],[1,484],[1,484],[1,484],[1,485],[1,485],[1,485],[1,485],[1,485],[1,486],[1,486],[1,486],[1,486],[1,486],[1,487],[1,487],[1,487],[1,487],[1,487],[1,488],[1,488],[1,488],[1,488],[1,488],[1,489],[1,489],[1,489],[1,489],[1,489],[1,490],[1,490],[1,490],[1,490],[1,490],[1,491],[1,491],[1,491],[1,491],[1,491],[1,492],[1,492],[1,492],[1,492],[1,492],[1,493],[1,493],[1,493],[1,493],[1,493],[1,494],[1,494],[1,494],[1,494],[1,494],[1,495],[1,495],[1,495],[1,495],[1,495],[1,496],[1,496],[1,496],[1,496],[1,496],[1,497],[1,497],[1,497],[1,497],[1,497],[1,498],[1,498],[1,498],[1,498],[1,498],[1,499],[1,499],[1,499],[1,499],[1,499],[1,500],[1,500],[1,500],[1,500],[1,500],[2,2],[2,2],[2,2],[2,2],[2,2],[2,3],[2,3],[2,3],[2,3],[2,3],[2,4],[2,4],[2,4],[2,4],[2,4],[2,5],[2,5],[2,5],[2,5],[2,5],[2,6],[2,6],[2,6],[2,6],[2,6],[2,7],[2,7],[2,7],[2,7],[2,7],[2,8],[2,8],[2,8],[2,8],[2,8],[2,9],[2,9],[2,9],[2,9],[2,9],[2,10],[2,10],[2,10],[2,10],[2,10],[2,11],[2,11],[2,11],[2,11],[2,11],[2,12],[2,12],[2,12],[2,12],[2,12],[2,13],[2,13],[2,13],[2,13],[2,13],[2,14],[2,14],[2,14],[2,14],[2,14],[2,15],[2,15],[2,15],[2,15],[2,15],[2,16],[2,16],[2,16],[2,16],[2,16],[2,17],[2,17],[2,17],[2,17],[2,17],[2,18],[2,18],[2,18],[2,18],[2,18],[2,19],[2,19],[2,19],[2,19],[2,19],[2,20],[2,20],[2,20],[2,20],[2,20],[2,21],[2,21],[2,21],[2,21],[2,21],[2,22],[2,22],[2,22],[2,22],[2,22],[2,23],[2,23],[2,23],[2,23],[2,23],[2,24],[2,24],[2,24],[2,24],[2,24],[2,25],[2,25],[2,25],[2,25],[2,25],[2,26],[2,26],[2,26],[2,26],[2,26],[2,27],[2,27],[2,27],[2,27],[2,27],[2,28],[2,28],[2,28],[2,28],[2,28],[2,29],[2,29],[2,29],[2,29],[2,29],[2,30],[2,30],[2,30],[2,30],[2,30],[2,31],[2,31],[2,31],[2,31],[2,31],[2,32],[2,32],[2,32],[2,32],[2,32],[2,33],[2,33],[2,33],[2,33],[2,33],[2,34],[2,34],[2,34],[2,34],[2,34],[2,35],[2,35],[2,35],[2,35],[2,35],[2,36],[2,36],[2,36],[2,36],[2,36],[2,37],[2,37],[2,37],[2,37],[2,37],[2,38],[2,38],[2,38],[2,38],[2,38],[2,39],[2,39],[2,39],[2,39],[2,39],[2,40],[2,40],[2,40],[2,40],[2,40],[2,41],[2,41],[2,41],[2,41],[2,41],[2,42],[2,42],[2,42],[2,42],[2,42],[2,43],[2,43],[2,43],[2,43],[2,43],[2,44],[2,44],[2,44],[2,44],[2,44],[2,45],[2,45],[2,45],[2,45],[2,45],[2,46],[2,46],[2,46],[2,46],[2,46],[2,47],[2,47],[2,47],[2,47],[2,47],[2,48],[2,48],[2,48],[2,48],[2,48],[2,49],[2,49],[2,49],[2,49],[2,49],[2,50],[2,50],[2,50],[2,50],[2,50],[2,51],[2,51],[2,51],[2,51],[2,51],[2,52],[2,52],[2,52],[2,52],[2,52],[2,53],[2,53],[2,53],[2,53],[2,53],[2,54],[2,54],[2,54],[2,54],[2,54],[2,55],[2,55],[2,55],[2,55],[2,55],[2,56],[2,56],[2,56],[2,56],[2,56],[2,57],[2,57],[2,57],[2,57],[2,57],[2,58],[2,58],[2,58],[2,58],[2,58],[2,59],[2,59],[2,59],[2,59],[2,59],[2,60],[2,60],[2,60],[2,60],[2,60],[2,61],[2,61],[2,61],[2,61],[2,61],[2,62],[2,62],[2,62],[2,62],[2,62],[2,63],[2,63],[2,63],[2,63],[2,63],[2,64],[2,64],[2,64],[2,64],[2,64],[2,65],[2,65],[2,65],[2,65],[2,65],[2,66],[2,66],[2,66],[2,66],[2,66],[2,67],[2,67],[2,67],[2,67],[2,67],[2,68],[2,68],[2,68],[2,68],[2,68],[2,69],[2,69],[2,69],[2,69],[2,69],[2,70],[2,70],[2,70],[2,70],[2,70],[2,71],[2,71],[2,71],[2,71],[2,71],[2,72],[2,72],[2,72],[2,72],[2,72],[2,73],[2,73],[2,73],[2,73],[2,73],[2,74],[2,74],[2,74],[2,74],[2,74],[2,75],[2,75],[2,75],[2,75],[2,75],[2,76],[2,76],[2,76],[2,76],[2,76],[2,77],[2,77],[2,77],[2,77],[2,77],[2,78],[2,78],[2,78],[2,78],[2,78],[2,79],[2,79],[2,79],[2,79],[2,79],[2,80],[2,80],[2,80],[2,80],[2,80],[2,81],[2,81],[2,81],[2,81],[2,81],[2,82],[2,82],[2,82],[2,82],[2,82],[2,83],[2,83],[2,83],[2,83],[2,83],[2,84],[2,84],[2,84],[2,84],[2,84],[2,85],[2,85],[2,85],[2,85],[2,85],[2,86],[2,86],[2,86],[2,86],[2,86],[2,87],[2,87],[2,87],[2,87],[2,87],[2,88],[2,88],[2,88],[2,88],[2,88],[2,89],[2,89],[2,89],[2,89],[2,89],[2,90],[2,90],[2,90],[2,90],[2,90],[2,91],[2,91],[2,91],[2,91],[2,91],[2,92],[2,92],[2,92],[2,92],[2,92],[2,93],[2,93],[2,93],[2,93],[2,93],[2,94],[2,94],[2,94],[2,94],[2,94],[2,95],[2,95],[2,95],[2,95],[2,95],[2,96],[2,96],[2,96],[2,96],[2,96],[2,97],[2,97],[2,97],[2,97],[2,97],[2,98],[2,98],[2,98],[2,98],[2,98],[2,99],[2,99],[2,99],[2,99],[2,99],[2,100],[2,100],[2,100],[2,100],[2,100],[2,101],[2,101],[2,101],[2,101],[2,101],[2,102],[2,102],[2,102],[2,102],[2,102],[2,103],[2,103],[2,103],[2,103],[2,103],[2,104],[2,104],[2,104],[2,104],[2,104],[2,105],[2,105],[2,105],[2,105],[2,105],[2,106],[2,106],[2,106],[2,106],[2,106],[2,107],[2,107],[2,107],[2,107],[2,107],[2,108],[2,108],[2,108],[2,108],[2,108],[2,109],[2,109],[2,109],[2,109],[2,109],[2,110],[2,110],[2,110],[2,110],[2,110],[2,111],[2,111],[2,111],[2,111],[2,111],[2,112],[2,112],[2,112],[2,112],[2,112],[2,113],[2,113],[2,113],[2,113],[2,113],[2,114],[2,114],[2,114],[2,114],[2,114],[2,115],[2,115],[2,115],[2,115],[2,115],[2,116],[2,116],[2,116],[2,116],[2,116],[2,117],[2,117],[2,117],[2,117],[2,117],[2,118],[2,118],[2,118],[2,118],[2,118],[2,119],[2,119],[2,119],[2,119],[2,119],[2,120],[2,120],[2,120],[2,120],[2,120],[2,121],[2,121],[2,121],[2,121],[2,121],[2,122],[2,122],[2,122],[2,122],[2,122],[2,123],[2,123],[2,123],[2,123],[2,123],[2,124],[2,124],[2,124],[2,124],[2,124],[2,125],[2,125],[2,125],[2,125],[2,125],[2,126],[2,126],[2,126],[2,126],[2,126],[2,127],[2,127],[2,127],[2,127],[2,127],[2,128],[2,128],[2,128],[2,128],[2,128],[2,129],[2,129],[2,129],[2,129],[2,129],[2,130],[2,130],[2,130],[2,130],[2,130],[2,131],[2,131],[2,131],[2,131],[2,131],[2,132],[2,132],[2,132],[2,132],[2,132],[2,133],[2,133],[2,133],[2,133],[2,133],[2,134],[2,134],[2,134],[2,134],[2,134],[2,135],[2,135],[2,135],[2,135],[2,135],[2,136],[2,136],[2,136],[2,136],[2,136],[2,137],[2,137],[2,137],[2,137],[2,137],[2,138],[2,138],[2,138],[2,138],[2,138],[2,139],[2,139],[2,139],[2,139],[2,139],[2,140],[2,140],[2,140],[2,140],[2,140],[2,141],[2,141],[2,141],[2,141],[2,141],[2,142],[2,142],[2,142],[2,142],[2,142],[2,143],[2,143],[2,143],[2,143],[2,143],[2,144],[2,144],[2,144],[2,144],[2,144],[2,145],[2,145],[2,145],[2,145],[2,145],[2,146],[2,146],[2,146],[2,146],[2,146],[2,147],[2,147],[2,147],[2,147],[2,147],[2,148],[2,148],[2,148],[2,148],[2,148],[2,149],[2,149],[2,149],[2,149],[2,149],[2,150],[2,150],[2,150],[2,150],[2,150],[2,151],[2,151],[2,151],[2,151],[2,151],[2,152],[2,152],[2,152],[2,152],[2,152],[2,153],[2,153],[2,153],[2,153],[2,153],[2,154],[2,154],[2,154],[2,154],[2,154],[2,155],[2,155],[2,155],[2,155],[2,155],[2,156],[2,156],[2,156],[2,156],[2,156],[2,157],[2,157],[2,157],[2,157],[2,157],[2,158],[2,158],[2,158],[2,158],[2,158],[2,159],[2,159],[2,159],[2,159],[2,159],[2,160],[2,160],[2,160],[2,160],[2,160],[2,161],[2,161],[2,161],[2,161],[2,161],[2,162],[2,162],[2,162],[2,162],[2,162],[2,163],[2,163],[2,163],[2,163],[2,163],[2,164],[2,164],[2,164],[2,164],[2,164],[2,165],[2,165],[2,165],[2,165],[2,165],[2,166],[2,166],[2,166],[2,166],[2,166],[2,167],[2,167],[2,167],[2,167],[2,167],[2,168],[2,168],[2,168],[2,168],[2,168],[2,169],[2,169],[2,169],[2,169],[2,169],[2,170],[2,170],[2,170],[2,170],[2,170],[2,171],[2,171],[2,171],[2,171],[2,171],[2,172],[2,172],[2,172],[2,172],[2,172],[2,173],[2,173],[2,173],[2,173],[2,173],[2,174],[2,174],[2,174],[2,174],[2,174],[2,175],[2,175],[2,175],[2,175],[2,175],[2,176],[2,176],[2,176],[2,176],[2,176],[2,177],[2,177],[2,177],[2,177],[2,177],[2,178],[2,178],[2,178],[2,178],[2,178],[2,179],[2,179],[2,179],[2,179],[2,179],[2,180],[2,180],[2,180],[2,180],[2,180],[2,181],[2,181],[2,181],[2,181],[2,181],[2,182],[2,182],[2,182],[2,182],[2,182],[2,183],[2,183],[2,183],[2,183],[2,183],[2,184],[2,184],[2,184],[2,184],[2,184],[2,185],[2,185],[2,185],[2,185],[2,185],[2,186],[2,186],[2,186],[2,186],[2,186],[2,187],[2,187],[2,187],[2,187],[2,187],[2,188],[2,188],[2,188],[2,188],[2,188],[2,189],[2,189],[2,189],[2,189],[2,189],[2,190],[2,190],[2,190],[2,190],[2,190],[2,191],[2,191],[2,191],[2,191],[2,191],[2,192],[2,192],[2,192],[2,192],[2,192],[2,193],[2,193],[2,193],[2,193],[2,193],[2,194],[2,194],[2,194],[2,194],[2,194],[2,195],[2,195],[2,195],[2,195],[2,195],[2,196],[2,196],[2,196],[2,196],[2,196],[2,197],[2,197],[2,197],[2,197],[2,197],[2,198],[2,198],[2,198],[2,198],[2,198],[2,199],[2,199],[2,199],[2,199],[2,199],[2,200],[2,200],[2,200],[2,200],[2,200],[2,201],[2,201],[2,201],[2,201],[2,201],[2,202],[2,202],[2,202],[2,202],[2,202],[2,203],[2,203],[2,203],[2,203],[2,203],[2,204],[2,204],[2,204],[2,204],[2,204],[2,205],[2,205],[2,205],[2,205],[2,205],[2,206],[2,206],[2,206],[2,206],[2,206],[2,207],[2,207],[2,207],[2,207],[2,207],[2,208],[2,208],[2,208],[2,208],[2,208],[2,209],[2,209],[2,209],[2,209],[2,209],[2,210],[2,210],[2,210],[2,210],[2,210],[2,211],[2,211],[2,211],[2,211],[2,211],[2,212],[2,212],[2,212],[2,212],[2,212],[2,213],[2,213],[2,213],[2,213],[2,213],[2,214],[2,214],[2,214],[2,214],[2,214],[2,215],[2,215],[2,215],[2,215],[2,215],[2,216],[2,216],[2,216],[2,216],[2,216],[2,217],[2,217],[2,217],[2,217],[2,217],[2,218],[2,218],[2,218],[2,218],[2,218],[2,219],[2,219],[2,219],[2,219],[2,219],[2,220],[2,220],[2,220],[2,220],[2,220],[2,221],[2,221],[2,221],[2,221],[2,221],[2,222],[2,222],[2,222],[2,222],[2,222],[2,223],[2,223],[2,223],[2,223],[2,223],[2,224],[2,224],[2,224],[2,224],[2,224],[2,225],[2,225],[2,225],[2,225],[2,225],[2,226],[2,226],[2,226],[2,226],[2,226],[2,227],[2,227],[2,227],[2,227],[2,227],[2,228],[2,228],[2,228],[2,228],[2,228],[2,229],[2,229],[2,229],[2,229],[2,229],[2,230],[2,230],[2,230],[2,230],[2,230],[2,231],[2,231],[2,231],[2,231],[2,231],[2,232],[2,232],[2,232],[2,232],[2,232],[2,233],[2,233],[2,233],[2,233],[2,233],[2,234],[2,234],[2,234],[2,234],[2,234],[2,235],[2,235],[2,235],[2,235],[2,235],[2,236],[2,236],[2,236],[2,236],[2,236],[2,237],[2,237],[2,237],[2,237],[2,237],[2,238],[2,238],[2,238],[2,238],[2,238],[2,239],[2,239],[2,239],[2,239],[2,239],[2,240],[2,240],[2,240],[2,240],[2,240],[2,241],[2,241],[2,241],[2,241],[2,241],[2,242],[2,242],[2,242],[2,242],[2,242],[2,243],[2,243],[2,243],[2,243],[2,243],[2,244],[2,244],[2,244],[2,244],[2,244],[2,245],[2,245],[2,245],[2,245],[2,245],[2,246],[2,246],[2,246],[2,246],[2,246],[2,247],[2,247],[2,247],[2,247],[2,247],[2,248],[2,248],[2,248],[2,248],[2,248],[2,249],[2,249],[2,249],[2,249],[2,249],[2,250],[2,250],[2,250],[2,250],[2,250],[2,251],[2,251],[2,251],[2,251],[2,251],[2,252],[2,252],[2,252],[2,252],[2,252],[2,253],[2,253],[2,253],[2,253],[2,253],[2,254],[2,254],[2,254],[2,254],[2,254],[2,255],[2,255],[2,255],[2,255],[2,255],[2,256],[2,256],[2,256],[2,256],[2,256],[2,257],[2,257],[2,257],[2,257],[2,257],[2,258],[2,258],[2,258],[2,258],[2,258],[2,259],[2,259],[2,259],[2,259],[2,259],[2,260],[2,260],[2,260],[2,260],[2,260],[2,261],[2,261],[2,261],[2,261],[2,261],[2,262],[2,262],[2,262],[2,262],[2,262],[2,263],[2,263],[2,263],[2,263],[2,263],[2,264],[2,264],[2,264],[2,264],[2,264],[2,265],[2,265],[2,265],[2,265],[2,265],[2,266],[2,266],[2,266],[2,266],[2,266],[2,267],[2,267],[2,267],[2,267],[2,267],[2,268],[2,268],[2,268],[2,268],[2,268],[2,269],[2,269],[2,269],[2,269],[2,269],[2,270],[2,270],[2,270],[2,270],[2,270],[2,271],[2,271],[2,271],[2,271],[2,271],[2,272],[2,272],[2,272],[2,272],[2,272],[2,273],[2,273],[2,273],[2,273],[2,273],[2,274],[2,274],[2,274],[2,274],[2,274],[2,275],[2,275],[2,275],[2,275],[2,275],[2,276],[2,276],[2,276],[2,276],[2,276],[2,277],[2,277],[2,277],[2,277],[2,277],[2,278],[2,278],[2,278],[2,278],[2,278],[2,279],[2,279],[2,279],[2,279],[2,279],[2,280],[2,280],[2,280],[2,280],[2,280],[2,281],[2,281],[2,281],[2,281],[2,281],[2,282],[2,282],[2,282],[2,282],[2,282],[2,283],[2,283],[2,283],[2,283],[2,283],[2,284],[2,284],[2,284],[2,284],[2,284],[2,285],[2,285],[2,285],[2,285],[2,285],[2,286],[2,286],[2,286],[2,286],[2,286],[2,287],[2,287],[2,287],[2,287],[2,287],[2,288],[2,288],[2,288],[2,288],[2,288],[2,289],[2,289],[2,289],[2,289],[2,289],[2,290],[2,290],[2,290],[2,290],[2,290],[2,291],[2,291],[2,291],[2,291],[2,291],[2,292],[2,292],[2,292],[2,292],[2,292],[2,293],[2,293],[2,293],[2,293],[2,293],[2,294],[2,294],[2,294],[2,294],[2,294],[2,295],[2,295],[2,295],[2,295],[2,295],[2,296],[2,296],[2,296],[2,296],[2,296],[2,297],[2,297],[2,297],[2,297],[2,297],[2,298],[2,298],[2,298],[2,298],[2,298],[2,299],[2,299],[2,299],[2,299],[2,299],[2,300],[2,300],[2,300],[2,300],[2,300],[2,301],[2,301],[2,301],[2,301],[2,301],[2,302],[2,302],[2,302],[2,302],[2,302],[2,303],[2,303],[2,303],[2,303],[2,303],[2,304],[2,304],[2,304],[2,304],[2,304],[2,305],[2,305],[2,305],[2,305],[2,305],[2,306],[2,306],[2,306],[2,306],[2,306],[2,307],[2,307],[2,307],[2,307],[2,307],[2,308],[2,308],[2,308],[2,308],[2,308],[2,309],[2,309],[2,309],[2,309],[2,309],[2,310],[2,310],[2,310],[2,310],[2,310],[2,311],[2,311],[2,311],[2,311],[2,311],[2,312],[2,312],[2,312],[2,312],[2,312],[2,313],[2,313],[2,313],[2,313],[2,313],[2,314],[2,314],[2,314],[2,314],[2,314],[2,315],[2,315],[2,315],[2,315],[2,315],[2,316],[2,316],[2,316],[2,316],[2,316],[2,317],[2,317],[2,317],[2,317],[2,317],[2,318],[2,318],[2,318],[2,318],[2,318],[2,319],[2,319],[2,319],[2,319],[2,319],[2,320],[2,320],[2,320],[2,320],[2,320],[2,321],[2,321],[2,321],[2,321],[2,321],[2,322],[2,322],[2,322],[2,322],[2,322],[2,323],[2,323],[2,323],[2,323],[2,323],[2,324],[2,324],[2,324],[2,324],[2,324],[2,325],[2,325],[2,325],[2,325],[2,325],[2,326],[2,326],[2,326],[2,326],[2,326],[2,327],[2,327],[2,327],[2,327],[2,327],[2,328],[2,328],[2,328],[2,328],[2,328],[2,329],[2,329],[2,329],[2,329],[2,329],[2,330],[2,330],[2,330],[2,330],[2,330],[2,331],[2,331],[2,331],[2,331],[2,331],[2,332],[2,332],[2,332],[2,332],[2,332],[2,333],[2,333],[2,333],[2,333],[2,333],[2,334],[2,334],[2,334],[2,334],[2,334],[2,335],[2,335],[2,335],[2,335],[2,335],[2,336],[2,336],[2,336],[2,336],[2,336],[2,337],[2,337],[2,337],[2,337],[2,337],[2,338],[2,338],[2,338],[2,338],[2,338],[2,339],[2,339],[2,339],[2,339],[2,339],[2,340],[2,340],[2,340],[2,340],[2,340],[2,341],[2,341],[2,341],[2,341],[2,341],[2,342],[2,342],[2,342],[2,342],[2,342],[2,343],[2,343],[2,343],[2,343],[2,343],[2,344],[2,344],[2,344],[2,344],[2,344],[2,345],[2,345],[2,345],[2,345],[2,345],[2,346],[2,346],[2,346],[2,346],[2,346],[2,347],[2,347],[2,347],[2,347],[2,347],[2,348],[2,348],[2,348],[2,348],[2,348],[2,349],[2,349],[2,349],[2,349],[2,349],[2,350],[2,350],[2,350],[2,350],[2,350],[2,351],[2,351],[2,351],[2,351],[2,351],[2,352],[2,352],[2,352],[2,352],[2,352],[2,353],[2,353],[2,353],[2,353],[2,353],[2,354],[2,354],[2,354],[2,354],[2,354],[2,355],[2,355],[2,355],[2,355],[2,355],[2,356],[2,356],[2,356],[2,356],[2,356],[2,357],[2,357],[2,357],[2,357],[2,357],[2,358],[2,358],[2,358],[2,358],[2,358],[2,359],[2,359],[2,359],[2,359],[2,359],[2,360],[2,360],[2,360],[2,360],[2,360],[2,361],[2,361],[2,361],[2,361],[2,361],[2,362],[2,362],[2,362],[2,362],[2,362],[2,363],[2,363],[2,363],[2,363],[2,363],[2,364],[2,364],[2,364],[2,364],[2,364],[2,365],[2,365],[2,365],[2,365],[2,365],[2,366],[2,366],[2,366],[2,366],[2,366],[2,367],[2,367],[2,367],[2,367],[2,367],[2,368],[2,368],[2,368],[2,368],[2,368],[2,369],[2,369],[2,369],[2,369],[2,369],[2,370],[2,370],[2,370],[2,370],[2,370],[2,371],[2,371],[2,371],[2,371],[2,371],[2,372],[2,372],[2,372],[2,372],[2,372],[2,373],[2,373],[2,373],[2,373],[2,373],[2,374],[2,374],[2,374],[2,374],[2,374],[2,375],[2,375],[2,375],[2,375],[2,375],[2,376],[2,376],[2,376],[2,376],[2,376],[2,377],[2,377],[2,377],[2,377],[2,377],[2,378],[2,378],[2,378],[2,378],[2,378],[2,379],[2,379],[2,379],[2,379],[2,379],[2,380],[2,380],[2,380],[2,380],[2,380],[2,381],[2,381],[2,381],[2,381],[2,381],[2,382],[2,382],[2,382],[2,382],[2,382],[2,383],[2,383],[2,383],[2,383],[2,383],[2,384],[2,384],[2,384],[2,384],[2,384],[2,385],[2,385],[2,385],[2,385],[2,385],[2,386],[2,386],[2,386],[2,386],[2,386],[2,387],[2,387],[2,387],[2,387],[2,387],[2,388],[2,388],[2,388],[2,388],[2,388],[2,389],[2,389],[2,389],[2,389],[2,389],[2,390],[2,390],[2,390],[2,390],[2,390],[2,391],[2,391],[2,391],[2,391],[2,391],[2,392],[2,392],[2,392],[2,392],[2,392],[2,393],[2,393],[2,393],[2,393],[2,393],[2,394],[2,394],[2,394],[2,394],[2,394],[2,395],[2,395],[2,395],[2,395],[2,395],[2,396],[2,396],[2,396],[2,396],[2,396],[2,397],[2,397],[2,397],[2,397],[2,397],[2,398],[2,398],[2,398],[2,398],[2,398],[2,399],[2,399],[2,399],[2,399],[2,399],[2,400],[2,400],[2,400],[2,400],[2,400],[2,401],[2,401],[2,401],[2,401],[2,401],[2,402],[2,402],[2,402],[2,402],[2,402],[2,403],[2,403],[2,403],[2,403],[2,403],[2,404],[2,404],[2,404],[2,404],[2,404],[2,405],[2,405],[2,405],[2,405],[2,405],[2,406],[2,406],[2,406],[2,406],[2,406],[2,407],[2,407],[2,407],[2,407],[2,407],[2,408],[2,408],[2,408],[2,408],[2,408],[2,409],[2,409],[2,409],[2,409],[2,409],[2,410],[2,410],[2,410],[2,410],[2,410],[2,411],[2,411],[2,411],[2,411],[2,411],[2,412],[2,412],[2,412],[2,412],[2,412],[2,413],[2,413],[2,413],[2,413],[2,413],[2,414],[2,414],[2,414],[2,414],[2,414],[2,415],[2,415],[2,415],[2,415],[2,415],[2,416],[2,416],[2,416],[2,416],[2,416],[2,417],[2,417],[2,417],[2,417],[2,417],[2,418],[2,418],[2,418],[2,418],[2,418],[2,419],[2,419],[2,419],[2,419],[2,419],[2,420],[2,420],[2,420],[2,420],[2,420],[2,421],[2,421],[2,421],[2,421],[2,421],[2,422],[2,422],[2,422],[2,422],[2,422],[2,423],[2,423],[2,423],[2,423],[2,423],[2,424],[2,424],[2,424],[2,424],[2,424],[2,425],[2,425],[2,425],[2,425],[2,425],[2,426],[2,426],[2,426],[2,426],[2,426],[2,427],[2,427],[2,427],[2,427],[2,427],[2,428],[2,428],[2,428],[2,428],[2,428],[2,429],[2,429],[2,429],[2,429],[2,429],[2,430],[2,430],[2,430],[2,430],[2,430],[2,431],[2,431],[2,431],[2,431],[2,431],[2,432],[2,432],[2,432],[2,432],[2,432],[2,433],[2,433],[2,433],[2,433],[2,433],[2,434],[2,434],[2,434],[2,434],[2,434],[2,435],[2,435],[2,435],[2,435],[2,435],[2,436],[2,436],[2,436],[2,436],[2,436],[2,437],[2,437],[2,437],[2,437],[2,437],[2,438],[2,438],[2,438],[2,438],[2,438],[2,439],[2,439],[2,439],[2,439],[2,439],[2,440],[2,440],[2,440],[2,440],[2,440],[2,441],[2,441],[2,441],[2,441],[2,441],[2,442],[2,442],[2,442],[2,442],[2,442],[2,443],[2,443],[2,443],[2,443],[2,443],[2,444],[2,444],[2,444],[2,444],[2,444],[2,445],[2,445],[2,445],[2,445],[2,445],[2,446],[2,446],[2,446],[2,446],[2,446],[2,447],[2,447],[2,447],[2,447],[2,447],[2,448],[2,448],[2,448],[2,448],[2,448],[2,449],[2,449],[2,449],[2,449],[2,449],[2,450],[2,450],[2,450],[2,450],[2,450],[2,451],[2,451],[2,451],[2,451],[2,451],[2,452],[2,452],[2,452],[2,452],[2,452],[2,453],[2,453],[2,453],[2,453],[2,453],[2,454],[2,454],[2,454],[2,454],[2,454],[2,455],[2,455],[2,455],[2,455],[2,455],[2,456],[2,456],[2,456],[2,456],[2,456],[2,457],[2,457],[2,457],[2,457],[2,457],[2,458],[2,458],[2,458],[2,458],[2,458],[2,459],[2,459],[2,459],[2,459],[2,459],[2,460],[2,460],[2,460],[2,460],[2,460],[2,461],[2,461],[2,461],[2,461],[2,461],[2,462],[2,462],[2,462],[2,462],[2,462],[2,463],[2,463],[2,463],[2,463],[2,463],[2,464],[2,464],[2,464],[2,464],[2,464],[2,465],[2,465],[2,465],[2,465],[2,465],[2,466],[2,466],[2,466],[2,466],[2,466],[2,467],[2,467],[2,467],[2,467],[2,467],[2,468],[2,468],[2,468],[2,468],[2,468],[2,469],[2,469],[2,469],[2,469],[2,469],[2,470],[2,470],[2,470],[2,470],[2,470],[2,471],[2,471],[2,471],[2,471],[2,471],[2,472],[2,472],[2,472],[2,472],[2,472],[2,473],[2,473],[2,473],[2,473],[2,473],[2,474],[2,474],[2,474],[2,474],[2,474],[2,475],[2,475],[2,475],[2,475],[2,475],[2,476],[2,476],[2,476],[2,476],[2,476],[2,477],[2,477],[2,477],[2,477],[2,477],[2,478],[2,478],[2,478],[2,478],[2,478],[2,479],[2,479],[2,479],[2,479],[2,479],[2,480],[2,480],[2,480],[2,480],[2,480],[2,481],[2,481],[2,481],[2,481],[2,481],[2,482],[2,482],[2,482],[2,482],[2,482],[2,483],[2,483],[2,483],[2,483],[2,483],[2,484],[2,484],[2,484],[2,484],[2,484],[2,485],[2,485],[2,485],[2,485],[2,485],[2,486],[2,486],[2,486],[2,486],[2,486],[2,487],[2,487],[2,487],[2,487],[2,487],[2,488],[2,488],[2,488],[2,488],[2,488],[2,489],[2,489],[2,489],[2,489],[2,489],[2,490],[2,490],[2,490],[2,490],[2,490],[2,491],[2,491],[2,491],[2,491],[2,491],[2,492],[2,492],[2,492],[2,492],[2,492],[2,493],[2,493],[2,493],[2,493],[2,493],[2,494],[2,494],[2,494],[2,494],[2,494],[2,495],[2,495],[2,495],[2,495],[2,495],[2,496],[2,496],[2,496],[2,496],[2,496],[2,497],[2,497],[2,497],[2,497],[2,497],[2,498],[2,498],[2,498],[2,498],[2,498],[2,499],[2,499],[2,499],[2,499],[2,499],[2,500],[2,500],[2,500],[2,500],[2,500],[3,2],[3,2],[3,2],[3,2],[3,2],[3,3],[3,3],[3,3],[3,3],[3,3],[3,4],[3,4],[3,4],[3,4],[3,4],[3,5],[3,5],[3,5],[3,5],[3,5],[3,6],[3,6],[3,6],[3,6],[3,6],[3,7],[3,7],[3,7],[3,7],[3,7],[3,8],[3,8],[3,8],[3,8],[3,8],[3,9],[3,9],[3,9],[3,9],[3,9],[3,10],[3,10],[3,10],[3,10],[3,10],[3,11],[3,11],[3,11],[3,11],[3,11],[3,12],[3,12],[3,12],[3,12],[3,12],[3,13],[3,13],[3,13],[3,13],[3,13],[3,14],[3,14],[3,14],[3,14],[3,14],[3,15],[3,15],[3,15],[3,15],[3,15],[3,16],[3,16],[3,16],[3,16],[3,16],[3,17],[3,17],[3,17],[3,17],[3,17],[3,18],[3,18],[3,18],[3,18],[3,18],[3,19],[3,19],[3,19],[3,19],[3,19],[3,20],[3,20],[3,20],[3,20],[3,20],[3,21],[3,21],[3,21],[3,21],[3,21],[3,22],[3,22],[3,22],[3,22],[3,22],[3,23],[3,23],[3,23],[3,23],[3,23],[3,24],[3,24],[3,24],[3,24],[3,24],[3,25],[3,25],[3,25],[3,25],[3,25],[3,26],[3,26],[3,26],[3,26],[3,26],[3,27],[3,27],[3,27],[3,27],[3,27],[3,28],[3,28],[3,28],[3,28],[3,28],[3,29],[3,29],[3,29],[3,29],[3,29],[3,30],[3,30],[3,30],[3,30],[3,30],[3,31],[3,31],[3,31],[3,31],[3,31],[3,32],[3,32],[3,32],[3,32],[3,32],[3,33],[3,33],[3,33],[3,33],[3,33],[3,34],[3,34],[3,34],[3,34],[3,34],[3,35],[3,35],[3,35],[3,35],[3,35],[3,36],[3,36],[3,36],[3,36],[3,36],[3,37],[3,37],[3,37],[3,37],[3,37],[3,38],[3,38],[3,38],[3,38],[3,38],[3,39],[3,39],[3,39],[3,39],[3,39],[3,40],[3,40],[3,40],[3,40],[3,40],[3,41],[3,41],[3,41],[3,41],[3,41],[3,42],[3,42],[3,42],[3,42],[3,42],[3,43],[3,43],[3,43],[3,43],[3,43],[3,44],[3,44],[3,44],[3,44],[3,44],[3,45],[3,45],[3,45],[3,45],[3,45],[3,46],[3,46],[3,46],[3,46],[3,46],[3,47],[3,47],[3,47],[3,47],[3,47],[3,48],[3,48],[3,48],[3,48],[3,48],[3,49],[3,49],[3,49],[3,49],[3,49],[3,50],[3,50],[3,50],[3,50],[3,50],[3,51],[3,51],[3,51],[3,51],[3,51],[3,52],[3,52],[3,52],[3,52],[3,52],[3,53],[3,53],[3,53],[3,53],[3,53],[3,54],[3,54],[3,54],[3,54],[3,54],[3,55],[3,55],[3,55],[3,55],[3,55],[3,56],[3,56],[3,56],[3,56],[3,56],[3,57],[3,57],[3,57],[3,57],[3,57],[3,58],[3,58],[3,58],[3,58],[3,58],[3,59],[3,59],[3,59],[3,59],[3,59],[3,60],[3,60],[3,60],[3,60],[3,60],[3,61],[3,61],[3,61],[3,61],[3,61],[3,62],[3,62],[3,62],[3,62],[3,62],[3,63],[3,63],[3,63],[3,63],[3,63],[3,64],[3,64],[3,64],[3,64],[3,64],[3,65],[3,65],[3,65],[3,65],[3,65],[3,66],[3,66],[3,66],[3,66],[3,66],[3,67],[3,67],[3,67],[3,67],[3,67],[3,68],[3,68],[3,68],[3,68],[3,68],[3,69],[3,69],[3,69],[3,69],[3,69],[3,70],[3,70],[3,70],[3,70],[3,70],[3,71],[3,71],[3,71],[3,71],[3,71],[3,72],[3,72],[3,72],[3,72],[3,72],[3,73],[3,73],[3,73],[3,73],[3,73],[3,74],[3,74],[3,74],[3,74],[3,74],[3,75],[3,75],[3,75],[3,75],[3,75],[3,76],[3,76],[3,76],[3,76],[3,76],[3,77],[3,77],[3,77],[3,77],[3,77],[3,78],[3,78],[3,78],[3,78],[3,78],[3,79],[3,79],[3,79],[3,79],[3,79],[3,80],[3,80],[3,80],[3,80],[3,80],[3,81],[3,81],[3,81],[3,81],[3,81],[3,82],[3,82],[3,82],[3,82],[3,82],[3,83],[3,83],[3,83],[3,83],[3,83],[3,84],[3,84],[3,84],[3,84],[3,84],[3,85],[3,85],[3,85],[3,85],[3,85],[3,86],[3,86],[3,86],[3,86],[3,86],[3,87],[3,87],[3,87],[3,87],[3,87],[3,88],[3,88],[3,88],[3,88],[3,88],[3,89],[3,89],[3,89],[3,89],[3,89],[3,90],[3,90],[3,90],[3,90],[3,90],[3,91],[3,91],[3,91],[3,91],[3,91],[3,92],[3,92],[3,92],[3,92],[3,92],[3,93],[3,93],[3,93],[3,93],[3,93],[3,94],[3,94],[3,94],[3,94],[3,94],[3,95],[3,95],[3,95],[3,95],[3,95],[3,96],[3,96],[3,96],[3,96],[3,96],[3,97],[3,97],[3,97],[3,97],[3,97],[3,98],[3,98],[3,98],[3,98],[3,98],[3,99],[3,99],[3,99],[3,99],[3,99],[3,100],[3,100],[3,100],[3,100],[3,100],[3,101],[3,101],[3,101],[3,101],[3,101],[3,102],[3,102],[3,102],[3,102],[3,102],[3,103],[3,103],[3,103],[3,103],[3,103],[3,104],[3,104],[3,104],[3,104],[3,104],[3,105],[3,105],[3,105],[3,105],[3,105],[3,106],[3,106],[3,106],[3,106],[3,106],[3,107],[3,107],[3,107],[3,107],[3,107],[3,108],[3,108],[3,108],[3,108],[3,108],[3,109],[3,109],[3,109],[3,109],[3,109],[3,110],[3,110],[3,110],[3,110],[3,110],[3,111],[3,111],[3,111],[3,111],[3,111],[3,112],[3,112],[3,112],[3,112],[3,112],[3,113],[3,113],[3,113],[3,113],[3,113],[3,114],[3,114],[3,114],[3,114],[3,114],[3,115],[3,115],[3,115],[3,115],[3,115],[3,116],[3,116],[3,116],[3,116],[3,116],[3,117],[3,117],[3,117],[3,117],[3,117],[3,118],[3,118],[3,118],[3,118],[3,118],[3,119],[3,119],[3,119],[3,119],[3,119],[3,120],[3,120],[3,120],[3,120],[3,120],[3,121],[3,121],[3,121],[3,121],[3,121],[3,122],[3,122],[3,122],[3,122],[3,122],[3,123],[3,123],[3,123],[3,123],[3,123],[3,124],[3,124],[3,124],[3,124],[3,124],[3,125],[3,125],[3,125],[3,125],[3,125],[3,126],[3,126],[3,126],[3,126],[3,126],[3,127],[3,127],[3,127],[3,127],[3,127],[3,128],[3,128],[3,128],[3,128],[3,128],[3,129],[3,129],[3,129],[3,129],[3,129],[3,130],[3,130],[3,130],[3,130],[3,130],[3,131],[3,131],[3,131],[3,131],[3,131],[3,132],[3,132],[3,132],[3,132],[3,132],[3,133],[3,133],[3,133],[3,133],[3,133],[3,134],[3,134],[3,134],[3,134],[3,134],[3,135],[3,135],[3,135],[3,135],[3,135],[3,136],[3,136],[3,136],[3,136],[3,136],[3,137],[3,137],[3,137],[3,137],[3,137],[3,138],[3,138],[3,138],[3,138],[3,138],[3,139],[3,139],[3,139],[3,139],[3,139],[3,140],[3,140],[3,140],[3,140],[3,140],[3,141],[3,141],[3,141],[3,141],[3,141],[3,142],[3,142],[3,142],[3,142],[3,142],[3,143],[3,143],[3,143],[3,143],[3,143],[3,144],[3,144],[3,144],[3,144],[3,144],[3,145],[3,145],[3,145],[3,145],[3,145],[3,146],[3,146],[3,146],[3,146],[3,146],[3,147],[3,147],[3,147],[3,147],[3,147],[3,148],[3,148],[3,148],[3,148],[3,148],[3,149],[3,149],[3,149],[3,149],[3,149],[3,150],[3,150],[3,150],[3,150],[3,150],[3,151],[3,151],[3,151],[3,151],[3,151],[3,152],[3,152],[3,152],[3,152],[3,152],[3,153],[3,153],[3,153],[3,153],[3,153],[3,154],[3,154],[3,154],[3,154],[3,154],[3,155],[3,155],[3,155],[3,155],[3,155],[3,156],[3,156],[3,156],[3,156],[3,156],[3,157],[3,157],[3,157],[3,157],[3,157],[3,158],[3,158],[3,158],[3,158],[3,158],[3,159],[3,159],[3,159],[3,159],[3,159],[3,160],[3,160],[3,160],[3,160],[3,160],[3,161],[3,161],[3,161],[3,161],[3,161],[3,162],[3,162],[3,162],[3,162],[3,162],[3,163],[3,163],[3,163],[3,163],[3,163],[3,164],[3,164],[3,164],[3,164],[3,164],[3,165],[3,165],[3,165],[3,165],[3,165],[3,166],[3,166],[3,166],[3,166],[3,166],[3,167],[3,167],[3,167],[3,167],[3,167],[3,168],[3,168],[3,168],[3,168],[3,168],[3,169],[3,169],[3,169],[3,169],[3,169],[3,170],[3,170],[3,170],[3,170],[3,170],[3,171],[3,171],[3,171],[3,171],[3,171],[3,172],[3,172],[3,172],[3,172],[3,172],[3,173],[3,173],[3,173],[3,173],[3,173],[3,174],[3,174],[3,174],[3,174],[3,174],[3,175],[3,175],[3,175],[3,175],[3,175],[3,176],[3,176],[3,176],[3,176],[3,176],[3,177],[3,177],[3,177],[3,177],[3,177],[3,178],[3,178],[3,178],[3,178],[3,178],[3,179],[3,179],[3,179],[3,179],[3,179],[3,180],[3,180],[3,180],[3,180],[3,180],[3,181],[3,181],[3,181],[3,181],[3,181],[3,182],[3,182],[3,182],[3,182],[3,182],[3,183],[3,183],[3,183],[3,183],[3,183],[3,184],[3,184],[3,184],[3,184],[3,184],[3,185],[3,185],[3,185],[3,185],[3,185],[3,186],[3,186],[3,186],[3,186],[3,186],[3,187],[3,187],[3,187],[3,187],[3,187],[3,188],[3,188],[3,188],[3,188],[3,188],[3,189],[3,189],[3,189],[3,189],[3,189],[3,190],[3,190],[3,190],[3,190],[3,190],[3,191],[3,191],[3,191],[3,191],[3,191],[3,192],[3,192],[3,192],[3,192],[3,192],[3,193],[3,193],[3,193],[3,193],[3,193],[3,194],[3,194],[3,194],[3,194],[3,194],[3,195],[3,195],[3,195],[3,195],[3,195],[3,196],[3,196],[3,196],[3,196],[3,196],[3,197],[3,197],[3,197],[3,197],[3,197],[3,198],[3,198],[3,198],[3,198],[3,198],[3,199],[3,199],[3,199],[3,199],[3,199],[3,200],[3,200],[3,200],[3,200],[3,200],[3,201],[3,201],[3,201],[3,201],[3,201],[3,202],[3,202],[3,202],[3,202],[3,202],[3,203],[3,203],[3,203],[3,203],[3,203],[3,204],[3,204],[3,204],[3,204],[3,204],[3,205],[3,205],[3,205],[3,205],[3,205],[3,206],[3,206],[3,206],[3,206],[3,206],[3,207],[3,207],[3,207],[3,207],[3,207],[3,208],[3,208],[3,208],[3,208],[3,208],[3,209],[3,209],[3,209],[3,209],[3,209],[3,210],[3,210],[3,210],[3,210],[3,210],[3,211],[3,211],[3,211],[3,211],[3,211],[3,212],[3,212],[3,212],[3,212],[3,212],[3,213],[3,213],[3,213],[3,213],[3,213],[3,214],[3,214],[3,214],[3,214],[3,214],[3,215],[3,215],[3,215],[3,215],[3,215],[3,216],[3,216],[3,216],[3,216],[3,216],[3,217],[3,217],[3,217],[3,217],[3,217],[3,218],[3,218],[3,218],[3,218],[3,218],[3,219],[3,219],[3,219],[3,219],[3,219],[3,220],[3,220],[3,220],[3,220],[3,220],[3,221],[3,221],[3,221],[3,221],[3,221],[3,222],[3,222],[3,222],[3,222],[3,222],[3,223],[3,223],[3,223],[3,223],[3,223],[3,224],[3,224],[3,224],[3,224],[3,224],[3,225],[3,225],[3,225],[3,225],[3,225],[3,226],[3,226],[3,226],[3,226],[3,226],[3,227],[3,227],[3,227],[3,227],[3,227],[3,228],[3,228],[3,228],[3,228],[3,228],[3,229],[3,229],[3,229],[3,229],[3,229],[3,230],[3,230],[3,230],[3,230],[3,230],[3,231],[3,231],[3,231],[3,231],[3,231],[3,232],[3,232],[3,232],[3,232],[3,232],[3,233],[3,233],[3,233],[3,233],[3,233],[3,234],[3,234],[3,234],[3,234],[3,234],[3,235],[3,235],[3,235],[3,235],[3,235],[3,236],[3,236],[3,236],[3,236],[3,236],[3,237],[3,237],[3,237],[3,237],[3,237],[3,238],[3,238],[3,238],[3,238],[3,238],[3,239],[3,239],[3,239],[3,239],[3,239],[3,240],[3,240],[3,240],[3,240],[3,240],[3,241],[3,241],[3,241],[3,241],[3,241],[3,242],[3,242],[3,242],[3,242],[3,242],[3,243],[3,243],[3,243],[3,243],[3,243],[3,244],[3,244],[3,244],[3,244],[3,244],[3,245],[3,245],[3,245],[3,245],[3,245],[3,246],[3,246],[3,246],[3,246],[3,246],[3,247],[3,247],[3,247],[3,247],[3,247],[3,248],[3,248],[3,248],[3,248],[3,248],[3,249],[3,249],[3,249],[3,249],[3,249],[3,250],[3,250],[3,250],[3,250],[3,250],[3,251],[3,251],[3,251],[3,251],[3,251],[3,252],[3,252],[3,252],[3,252],[3,252],[3,253],[3,253],[3,253],[3,253],[3,253],[3,254],[3,254],[3,254],[3,254],[3,254],[3,255],[3,255],[3,255],[3,255],[3,255],[3,256],[3,256],[3,256],[3,256],[3,256],[3,257],[3,257],[3,257],[3,257],[3,257],[3,258],[3,258],[3,258],[3,258],[3,258],[3,259],[3,259],[3,259],[3,259],[3,259],[3,260],[3,260],[3,260],[3,260],[3,260],[3,261],[3,261],[3,261],[3,261],[3,261],[3,262],[3,262],[3,262],[3,262],[3,262],[3,263],[3,263],[3,263],[3,263],[3,263],[3,264],[3,264],[3,264],[3,264],[3,264],[3,265],[3,265],[3,265],[3,265],[3,265],[3,266],[3,266],[3,266],[3,266],[3,266],[3,267],[3,267],[3,267],[3,267],[3,267],[3,268],[3,268],[3,268],[3,268],[3,268],[3,269],[3,269],[3,269],[3,269],[3,269],[3,270],[3,270],[3,270],[3,270],[3,270],[3,271],[3,271],[3,271],[3,271],[3,271],[3,272],[3,272],[3,272],[3,272],[3,272],[3,273],[3,273],[3,273],[3,273],[3,273],[3,274],[3,274],[3,274],[3,274],[3,274],[3,275],[3,275],[3,275],[3,275],[3,275],[3,276],[3,276],[3,276],[3,276],[3,276],[3,277],[3,277],[3,277],[3,277],[3,277],[3,278],[3,278],[3,278],[3,278],[3,278],[3,279],[3,279],[3,279],[3,279],[3,279],[3,280],[3,280],[3,280],[3,280],[3,280],[3,281],[3,281],[3,281],[3,281],[3,281],[3,282],[3,282],[3,282],[3,282],[3,282],[3,283],[3,283],[3,283],[3,283],[3,283],[3,284],[3,284],[3,284],[3,284],[3,284],[3,285],[3,285],[3,285],[3,285],[3,285],[3,286],[3,286],[3,286],[3,286],[3,286],[3,287],[3,287],[3,287],[3,287],[3,287],[3,288],[3,288],[3,288],[3,288],[3,288],[3,289],[3,289],[3,289],[3,289],[3,289],[3,290],[3,290],[3,290],[3,290],[3,290],[3,291],[3,291],[3,291],[3,291],[3,291],[3,292],[3,292],[3,292],[3,292],[3,292],[3,293],[3,293],[3,293],[3,293],[3,293],[3,294],[3,294],[3,294],[3,294],[3,294],[3,295],[3,295],[3,295],[3,295],[3,295],[3,296],[3,296],[3,296],[3,296],[3,296],[3,297],[3,297],[3,297],[3,297],[3,297],[3,298],[3,298],[3,298],[3,298],[3,298],[3,299],[3,299],[3,299],[3,299],[3,299],[3,300],[3,300],[3,300],[3,300],[3,300],[3,301],[3,301],[3,301],[3,301],[3,301],[3,302],[3,302],[3,302],[3,302],[3,302],[3,303],[3,303],[3,303],[3,303],[3,303],[3,304],[3,304],[3,304],[3,304],[3,304],[3,305],[3,305],[3,305],[3,305],[3,305],[3,306],[3,306],[3,306],[3,306],[3,306],[3,307],[3,307],[3,307],[3,307],[3,307],[3,308],[3,308],[3,308],[3,308],[3,308],[3,309],[3,309],[3,309],[3,309],[3,309],[3,310],[3,310],[3,310],[3,310],[3,310],[3,311],[3,311],[3,311],[3,311],[3,311],[3,312],[3,312],[3,312],[3,312],[3,312],[3,313],[3,313],[3,313],[3,313],[3,313],[3,314],[3,314],[3,314],[3,314],[3,314],[3,315],[3,315],[3,315],[3,315],[3,315],[3,316],[3,316],[3,316],[3,316],[3,316],[3,317],[3,317],[3,317],[3,317],[3,317],[3,318],[3,318],[3,318],[3,318],[3,318],[3,319],[3,319],[3,319],[3,319],[3,319],[3,320],[3,320],[3,320],[3,320],[3,320],[3,321],[3,321],[3,321],[3,321],[3,321],[3,322],[3,322],[3,322],[3,322],[3,322],[3,323],[3,323],[3,323],[3,323],[3,323],[3,324],[3,324],[3,324],[3,324],[3,324],[3,325],[3,325],[3,325],[3,325],[3,325],[3,326],[3,326],[3,326],[3,326],[3,326],[3,327],[3,327],[3,327],[3,327],[3,327],[3,328],[3,328],[3,328],[3,328],[3,328],[3,329],[3,329],[3,329],[3,329],[3,329],[3,330],[3,330],[3,330],[3,330],[3,330],[3,331],[3,331],[3,331],[3,331],[3,331],[3,332],[3,332],[3,332],[3,332],[3,332],[3,333],[3,333],[3,333],[3,333],[3,333],[3,334],[3,334],[3,334],[3,334],[3,334],[3,335],[3,335],[3,335],[3,335],[3,335],[3,336],[3,336],[3,336],[3,336],[3,336],[3,337],[3,337],[3,337],[3,337],[3,337],[3,338],[3,338],[3,338],[3,338],[3,338],[3,339],[3,339],[3,339],[3,339],[3,339],[3,340],[3,340],[3,340],[3,340],[3,340],[3,341],[3,341],[3,341],[3,341],[3,341],[3,342],[3,342],[3,342],[3,342],[3,342],[3,343],[3,343],[3,343],[3,343],[3,343],[3,344],[3,344],[3,344],[3,344],[3,344],[3,345],[3,345],[3,345],[3,345],[3,345],[3,346],[3,346],[3,346],[3,346],[3,346],[3,347],[3,347],[3,347],[3,347],[3,347],[3,348],[3,348],[3,348],[3,348],[3,348],[3,349],[3,349],[3,349],[3,349],[3,349],[3,350],[3,350],[3,350],[3,350],[3,350],[3,351],[3,351],[3,351],[3,351],[3,351],[3,352],[3,352],[3,352],[3,352],[3,352],[3,353],[3,353],[3,353],[3,353],[3,353],[3,354],[3,354],[3,354],[3,354],[3,354],[3,355],[3,355],[3,355],[3,355],[3,355],[3,356],[3,356],[3,356],[3,356],[3,356],[3,357],[3,357],[3,357],[3,357],[3,357],[3,358],[3,358],[3,358],[3,358],[3,358],[3,359],[3,359],[3,359],[3,359],[3,359],[3,360],[3,360],[3,360],[3,360],[3,360],[3,361],[3,361],[3,361],[3,361],[3,361],[3,362],[3,362],[3,362],[3,362],[3,362],[3,363],[3,363],[3,363],[3,363],[3,363],[3,364],[3,364],[3,364],[3,364],[3,364],[3,365],[3,365],[3,365],[3,365],[3,365],[3,366],[3,366],[3,366],[3,366],[3,366],[3,367],[3,367],[3,367],[3,367],[3,367],[3,368],[3,368],[3,368],[3,368],[3,368],[3,369],[3,369],[3,369],[3,369],[3,369],[3,370],[3,370],[3,370],[3,370],[3,370],[3,371],[3,371],[3,371],[3,371],[3,371],[3,372],[3,372],[3,372],[3,372],[3,372],[3,373],[3,373],[3,373],[3,373],[3,373],[3,374],[3,374],[3,374],[3,374],[3,374],[3,375],[3,375],[3,375],[3,375],[3,375],[3,376],[3,376],[3,376],[3,376],[3,376],[3,377],[3,377],[3,377],[3,377],[3,377],[3,378],[3,378],[3,378],[3,378],[3,378],[3,379],[3,379],[3,379],[3,379],[3,379],[3,380],[3,380],[3,380],[3,380],[3,380],[3,381],[3,381],[3,381],[3,381],[3,381],[3,382],[3,382],[3,382],[3,382],[3,382],[3,383],[3,383],[3,383],[3,383],[3,383],[3,384],[3,384],[3,384],[3,384],[3,384],[3,385],[3,385],[3,385],[3,385],[3,385],[3,386],[3,386],[3,386],[3,386],[3,386],[3,387],[3,387],[3,387],[3,387],[3,387],[3,388],[3,388],[3,388],[3,388],[3,388],[3,389],[3,389],[3,389],[3,389],[3,389],[3,390],[3,390],[3,390],[3,390],[3,390],[3,391],[3,391],[3,391],[3,391],[3,391],[3,392],[3,392],[3,392],[3,392],[3,392],[3,393],[3,393],[3,393],[3,393],[3,393],[3,394],[3,394],[3,394],[3,394],[3,394],[3,395],[3,395],[3,395],[3,395],[3,395],[3,396],[3,396],[3,396],[3,396],[3,396],[3,397],[3,397],[3,397],[3,397],[3,397],[3,398],[3,398],[3,398],[3,398],[3,398],[3,399],[3,399],[3,399],[3,399],[3,399],[3,400],[3,400],[3,400],[3,400],[3,400],[3,401],[3,401],[3,401],[3,401],[3,401],[3,402],[3,402],[3,402],[3,402],[3,402],[3,403],[3,403],[3,403],[3,403],[3,403],[3,404],[3,404],[3,404],[3,404],[3,404],[3,405],[3,405],[3,405],[3,405],[3,405],[3,406],[3,406],[3,406],[3,406],[3,406],[3,407],[3,407],[3,407],[3,407],[3,407],[3,408],[3,408],[3,408],[3,408],[3,408],[3,409],[3,409],[3,409],[3,409],[3,409],[3,410],[3,410],[3,410],[3,410],[3,410],[3,411],[3,411],[3,411],[3,411],[3,411],[3,412],[3,412],[3,412],[3,412],[3,412],[3,413],[3,413],[3,413],[3,413],[3,413],[3,414],[3,414],[3,414],[3,414],[3,414],[3,415],[3,415],[3,415],[3,415],[3,415],[3,416],[3,416],[3,416],[3,416],[3,416],[3,417],[3,417],[3,417],[3,417],[3,417],[3,418],[3,418],[3,418],[3,418],[3,418],[3,419],[3,419],[3,419],[3,419],[3,419],[3,420],[3,420],[3,420],[3,420],[3,420],[3,421],[3,421],[3,421],[3,421],[3,421],[3,422],[3,422],[3,422],[3,422],[3,422],[3,423],[3,423],[3,423],[3,423],[3,423],[3,424],[3,424],[3,424],[3,424],[3,424],[3,425],[3,425],[3,425],[3,425],[3,425],[3,426],[3,426],[3,426],[3,426],[3,426],[3,427],[3,427],[3,427],[3,427],[3,427],[3,428],[3,428],[3,428],[3,428],[3,428],[3,429],[3,429],[3,429],[3,429],[3,429],[3,430],[3,430],[3,430],[3,430],[3,430],[3,431],[3,431],[3,431],[3,431],[3,431],[3,432],[3,432],[3,432],[3,432],[3,432],[3,433],[3,433],[3,433],[3,433],[3,433],[3,434],[3,434],[3,434],[3,434],[3,434],[3,435],[3,435],[3,435],[3,435],[3,435],[3,436],[3,436],[3,436],[3,436],[3,436],[3,437],[3,437],[3,437],[3,437],[3,437],[3,438],[3,438],[3,438],[3,438],[3,438],[3,439],[3,439],[3,439],[3,439],[3,439],[3,440],[3,440],[3,440],[3,440],[3,440],[3,441],[3,441],[3,441],[3,441],[3,441],[3,442],[3,442],[3,442],[3,442],[3,442],[3,443],[3,443],[3,443],[3,443],[3,443],[3,444],[3,444],[3,444],[3,444],[3,444],[3,445],[3,445],[3,445],[3,445],[3,445],[3,446],[3,446],[3,446],[3,446],[3,446],[3,447],[3,447],[3,447],[3,447],[3,447],[3,448],[3,448],[3,448],[3,448],[3,448],[3,449],[3,449],[3,449],[3,449],[3,449],[3,450],[3,450],[3,450],[3,450],[3,450],[3,451],[3,451],[3,451],[3,451],[3,451],[3,452],[3,452],[3,452],[3,452],[3,452],[3,453],[3,453],[3,453],[3,453],[3,453],[3,454],[3,454],[3,454],[3,454],[3,454],[3,455],[3,455],[3,455],[3,455],[3,455],[3,456],[3,456],[3,456],[3,456],[3,456],[3,457],[3,457],[3,457],[3,457],[3,457],[3,458],[3,458],[3,458],[3,458],[3,458],[3,459],[3,459],[3,459],[3,459],[3,459],[3,460],[3,460],[3,460],[3,460],[3,460],[3,461],[3,461],[3,461],[3,461],[3,461],[3,462],[3,462],[3,462],[3,462],[3,462],[3,463],[3,463],[3,463],[3,463],[3,463],[3,464],[3,464],[3,464],[3,464],[3,464],[3,465],[3,465],[3,465],[3,465],[3,465],[3,466],[3,466],[3,466],[3,466],[3,466],[3,467],[3,467],[3,467],[3,467],[3,467],[3,468],[3,468],[3,468],[3,468],[3,468],[3,469],[3,469],[3,469],[3,469],[3,469],[3,470],[3,470],[3,470],[3,470],[3,470],[3,471],[3,471],[3,471],[3,471],[3,471],[3,472],[3,472],[3,472],[3,472],[3,472],[3,473],[3,473],[3,473],[3,473],[3,473],[3,474],[3,474],[3,474],[3,474],[3,474],[3,475],[3,475],[3,475],[3,475],[3,475],[3,476],[3,476],[3,476],[3,476],[3,476],[3,477],[3,477],[3,477],[3,477],[3,477],[3,478],[3,478],[3,478],[3,478],[3,478],[3,479],[3,479],[3,479],[3,479],[3,479],[3,480],[3,480],[3,480],[3,480],[3,480],[3,481],[3,481],[3,481],[3,481],[3,481],[3,482],[3,482],[3,482],[3,482],[3,482],[3,483],[3,483],[3,483],[3,483],[3,483],[3,484],[3,484],[3,484],[3,484],[3,484],[3,485],[3,485],[3,485],[3,485],[3,485],[3,486],[3,486],[3,486],[3,486],[3,486],[3,487],[3,487],[3,487],[3,487],[3,487],[3,488],[3,488],[3,488],[3,488],[3,488],[3,489],[3,489],[3,489],[3,489],[3,489],[3,490],[3,490],[3,490],[3,490],[3,490],[3,491],[3,491],[3,491],[3,491],[3,491],[3,492],[3,492],[3,492],[3,492],[3,492],[3,493],[3,493],[3,493],[3,493],[3,493],[3,494],[3,494],[3,494],[3,494],[3,494],[3,495],[3,495],[3,495],[3,495],[3,495],[3,496],[3,496],[3,496],[3,496],[3,496],[3,497],[3,497],[3,497],[3,497],[3,497],[3,498],[3,498],[3,498],[3,498],[3,498],[3,499],[3,499],[3,499],[3,499],[3,499],[3,500],[3,500],[3,500],[3,500],[3,500],[4,2],[4,2],[4,2],[4,2],[4,2],[4,3],[4,3],[4,3],[4,3],[4,3],[4,4],[4,4],[4,4],[4,4],[4,4],[4,5],[4,5],[4,5],[4,5],[4,5],[4,6],[4,6],[4,6],[4,6],[4,6],[4,7],[4,7],[4,7],[4,7],[4,7],[4,8],[4,8],[4,8],[4,8],[4,8],[4,9],[4,9],[4,9],[4,9],[4,9],[4,10],[4,10],[4,10],[4,10],[4,10],[4,11],[4,11],[4,11],[4,11],[4,11],[4,12],[4,12],[4,12],[4,12],[4,12],[4,13],[4,13],[4,13],[4,13],[4,13],[4,14],[4,14],[4,14],[4,14],[4,14],[4,15],[4,15],[4,15],[4,15],[4,15],[4,16],[4,16],[4,16],[4,16],[4,16],[4,17],[4,17],[4,17],[4,17],[4,17],[4,18],[4,18],[4,18],[4,18],[4,18],[4,19],[4,19],[4,19],[4,19],[4,19],[4,20],[4,20],[4,20],[4,20],[4,20],[4,21],[4,21],[4,21],[4,21],[4,21],[4,22],[4,22],[4,22],[4,22],[4,22],[4,23],[4,23],[4,23],[4,23],[4,23],[4,24],[4,24],[4,24],[4,24],[4,24],[4,25],[4,25],[4,25],[4,25],[4,25],[4,26],[4,26],[4,26],[4,26],[4,26],[4,27],[4,27],[4,27],[4,27],[4,27],[4,28],[4,28],[4,28],[4,28],[4,28],[4,29],[4,29],[4,29],[4,29],[4,29],[4,30],[4,30],[4,30],[4,30],[4,30],[4,31],[4,31],[4,31],[4,31],[4,31],[4,32],[4,32],[4,32],[4,32],[4,32],[4,33],[4,33],[4,33],[4,33],[4,33],[4,34],[4,34],[4,34],[4,34],[4,34],[4,35],[4,35],[4,35],[4,35],[4,35],[4,36],[4,36],[4,36],[4,36],[4,36],[4,37],[4,37],[4,37],[4,37],[4,37],[4,38],[4,38],[4,38],[4,38],[4,38],[4,39],[4,39],[4,39],[4,39],[4,39],[4,40],[4,40],[4,40],[4,40],[4,40],[4,41],[4,41],[4,41],[4,41],[4,41],[4,42],[4,42],[4,42],[4,42],[4,42],[4,43],[4,43],[4,43],[4,43],[4,43],[4,44],[4,44],[4,44],[4,44],[4,44],[4,45],[4,45],[4,45],[4,45],[4,45],[4,46],[4,46],[4,46],[4,46],[4,46],[4,47],[4,47],[4,47],[4,47],[4,47],[4,48],[4,48],[4,48],[4,48],[4,48],[4,49],[4,49],[4,49],[4,49],[4,49],[4,50],[4,50],[4,50],[4,50],[4,50],[4,51],[4,51],[4,51],[4,51],[4,51],[4,52],[4,52],[4,52],[4,52],[4,52],[4,53],[4,53],[4,53],[4,53],[4,53],[4,54],[4,54],[4,54],[4,54],[4,54],[4,55],[4,55],[4,55],[4,55],[4,55],[4,56],[4,56],[4,56],[4,56],[4,56],[4,57],[4,57],[4,57],[4,57],[4,57],[4,58],[4,58],[4,58],[4,58],[4,58],[4,59],[4,59],[4,59],[4,59],[4,59],[4,60],[4,60],[4,60],[4,60],[4,60],[4,61],[4,61],[4,61],[4,61],[4,61],[4,62],[4,62],[4,62],[4,62],[4,62],[4,63],[4,63],[4,63],[4,63],[4,63],[4,64],[4,64],[4,64],[4,64],[4,64],[4,65],[4,65],[4,65],[4,65],[4,65],[4,66],[4,66],[4,66],[4,66],[4,66],[4,67],[4,67],[4,67],[4,67],[4,67],[4,68],[4,68],[4,68],[4,68],[4,68],[4,69],[4,69],[4,69],[4,69],[4,69],[4,70],[4,70],[4,70],[4,70],[4,70],[4,71],[4,71],[4,71],[4,71],[4,71],[4,72],[4,72],[4,72],[4,72],[4,72],[4,73],[4,73],[4,73],[4,73],[4,73],[4,74],[4,74],[4,74],[4,74],[4,74],[4,75],[4,75],[4,75],[4,75],[4,75],[4,76],[4,76],[4,76],[4,76],[4,76],[4,77],[4,77],[4,77],[4,77],[4,77],[4,78],[4,78],[4,78],[4,78],[4,78],[4,79],[4,79],[4,79],[4,79],[4,79],[4,80],[4,80],[4,80],[4,80],[4,80],[4,81],[4,81],[4,81],[4,81],[4,81],[4,82],[4,82],[4,82],[4,82],[4,82],[4,83],[4,83],[4,83],[4,83],[4,83],[4,84],[4,84],[4,84],[4,84],[4,84],[4,85],[4,85],[4,85],[4,85],[4,85],[4,86],[4,86],[4,86],[4,86],[4,86],[4,87],[4,87],[4,87],[4,87],[4,87],[4,88],[4,88],[4,88],[4,88],[4,88],[4,89],[4,89],[4,89],[4,89],[4,89],[4,90],[4,90],[4,90],[4,90],[4,90],[4,91],[4,91],[4,91],[4,91],[4,91],[4,92],[4,92],[4,92],[4,92],[4,92],[4,93],[4,93],[4,93],[4,93],[4,93],[4,94],[4,94],[4,94],[4,94],[4,94],[4,95],[4,95],[4,95],[4,95],[4,95],[4,96],[4,96],[4,96],[4,96],[4,96],[4,97],[4,97],[4,97],[4,97],[4,97],[4,98],[4,98],[4,98],[4,98],[4,98],[4,99],[4,99],[4,99],[4,99],[4,99],[4,100],[4,100],[4,100],[4,100],[4,100],[4,101],[4,101],[4,101],[4,101],[4,101],[4,102],[4,102],[4,102],[4,102],[4,102],[4,103],[4,103],[4,103],[4,103],[4,103],[4,104],[4,104],[4,104],[4,104],[4,104],[4,105],[4,105],[4,105],[4,105],[4,105],[4,106],[4,106],[4,106],[4,106],[4,106],[4,107],[4,107],[4,107],[4,107],[4,107],[4,108],[4,108],[4,108],[4,108],[4,108],[4,109],[4,109],[4,109],[4,109],[4,109],[4,110],[4,110],[4,110],[4,110],[4,110],[4,111],[4,111],[4,111],[4,111],[4,111],[4,112],[4,112],[4,112],[4,112],[4,112],[4,113],[4,113],[4,113],[4,113],[4,113],[4,114],[4,114],[4,114],[4,114],[4,114],[4,115],[4,115],[4,115],[4,115],[4,115],[4,116],[4,116],[4,116],[4,116],[4,116],[4,117],[4,117],[4,117],[4,117],[4,117],[4,118],[4,118],[4,118],[4,118],[4,118],[4,119],[4,119],[4,119],[4,119],[4,119],[4,120],[4,120],[4,120],[4,120],[4,120],[4,121],[4,121],[4,121],[4,121],[4,121],[4,122],[4,122],[4,122],[4,122],[4,122],[4,123],[4,123],[4,123],[4,123],[4,123],[4,124],[4,124],[4,124],[4,124],[4,124],[4,125],[4,125],[4,125],[4,125],[4,125],[4,126],[4,126],[4,126],[4,126],[4,126],[4,127],[4,127],[4,127],[4,127],[4,127],[4,128],[4,128],[4,128],[4,128],[4,128],[4,129],[4,129],[4,129],[4,129],[4,129],[4,130],[4,130],[4,130],[4,130],[4,130],[4,131],[4,131],[4,131],[4,131],[4,131],[4,132],[4,132],[4,132],[4,132],[4,132],[4,133],[4,133],[4,133],[4,133],[4,133],[4,134],[4,134],[4,134],[4,134],[4,134],[4,135],[4,135],[4,135],[4,135],[4,135],[4,136],[4,136],[4,136],[4,136],[4,136],[4,137],[4,137],[4,137],[4,137],[4,137],[4,138],[4,138],[4,138],[4,138],[4,138],[4,139],[4,139],[4,139],[4,139],[4,139],[4,140],[4,140],[4,140],[4,140],[4,140],[4,141],[4,141],[4,141],[4,141],[4,141],[4,142],[4,142],[4,142],[4,142],[4,142],[4,143],[4,143],[4,143],[4,143],[4,143],[4,144],[4,144],[4,144],[4,144],[4,144],[4,145],[4,145],[4,145],[4,145],[4,145],[4,146],[4,146],[4,146],[4,146],[4,146],[4,147],[4,147],[4,147],[4,147],[4,147],[4,148],[4,148],[4,148],[4,148],[4,148],[4,149],[4,149],[4,149],[4,149],[4,149],[4,150],[4,150],[4,150],[4,150],[4,150],[4,151],[4,151],[4,151],[4,151],[4,151],[4,152],[4,152],[4,152],[4,152],[4,152],[4,153],[4,153],[4,153],[4,153],[4,153],[4,154],[4,154],[4,154],[4,154],[4,154],[4,155],[4,155],[4,155],[4,155],[4,155],[4,156],[4,156],[4,156],[4,156],[4,156],[4,157],[4,157],[4,157],[4,157],[4,157],[4,158],[4,158],[4,158],[4,158],[4,158],[4,159],[4,159],[4,159],[4,159],[4,159],[4,160],[4,160],[4,160],[4,160],[4,160],[4,161],[4,161],[4,161],[4,161],[4,161],[4,162],[4,162],[4,162],[4,162],[4,162],[4,163],[4,163],[4,163],[4,163],[4,163],[4,164],[4,164],[4,164],[4,164],[4,164],[4,165],[4,165],[4,165],[4,165],[4,165],[4,166],[4,166],[4,166],[4,166],[4,166],[4,167],[4,167],[4,167],[4,167],[4,167],[4,168],[4,168],[4,168],[4,168],[4,168],[4,169],[4,169],[4,169],[4,169],[4,169],[4,170],[4,170],[4,170],[4,170],[4,170],[4,171],[4,171],[4,171],[4,171],[4,171],[4,172],[4,172],[4,172],[4,172],[4,172],[4,173],[4,173],[4,173],[4,173],[4,173],[4,174],[4,174],[4,174],[4,174],[4,174],[4,175],[4,175],[4,175],[4,175],[4,175],[4,176],[4,176],[4,176],[4,176],[4,176],[4,177],[4,177],[4,177],[4,177],[4,177],[4,178],[4,178],[4,178],[4,178],[4,178],[4,179],[4,179],[4,179],[4,179],[4,179],[4,180],[4,180],[4,180],[4,180],[4,180],[4,181],[4,181],[4,181],[4,181],[4,181],[4,182],[4,182],[4,182],[4,182],[4,182],[4,183],[4,183],[4,183],[4,183],[4,183],[4,184],[4,184],[4,184],[4,184],[4,184],[4,185],[4,185],[4,185],[4,185],[4,185],[4,186],[4,186],[4,186],[4,186],[4,186],[4,187],[4,187],[4,187],[4,187],[4,187],[4,188],[4,188],[4,188],[4,188],[4,188],[4,189],[4,189],[4,189],[4,189],[4,189],[4,190],[4,190],[4,190],[4,190],[4,190],[4,191],[4,191],[4,191],[4,191],[4,191],[4,192],[4,192],[4,192],[4,192],[4,192],[4,193],[4,193],[4,193],[4,193],[4,193],[4,194],[4,194],[4,194],[4,194],[4,194],[4,195],[4,195],[4,195],[4,195],[4,195],[4,196],[4,196],[4,196],[4,196],[4,196],[4,197],[4,197],[4,197],[4,197],[4,197],[4,198],[4,198],[4,198],[4,198],[4,198],[4,199],[4,199],[4,199],[4,199],[4,199],[4,200],[4,200],[4,200],[4,200],[4,200],[4,201],[4,201],[4,201],[4,201],[4,201],[4,202],[4,202],[4,202],[4,202],[4,202],[4,203],[4,203],[4,203],[4,203],[4,203],[4,204],[4,204],[4,204],[4,204],[4,204],[4,205],[4,205],[4,205],[4,205],[4,205],[4,206],[4,206],[4,206],[4,206],[4,206],[4,207],[4,207],[4,207],[4,207],[4,207],[4,208],[4,208],[4,208],[4,208],[4,208],[4,209],[4,209],[4,209],[4,209],[4,209],[4,210],[4,210],[4,210],[4,210],[4,210],[4,211],[4,211],[4,211],[4,211],[4,211],[4,212],[4,212],[4,212],[4,212],[4,212],[4,213],[4,213],[4,213],[4,213],[4,213],[4,214],[4,214],[4,214],[4,214],[4,214],[4,215],[4,215],[4,215],[4,215],[4,215],[4,216],[4,216],[4,216],[4,216],[4,216],[4,217],[4,217],[4,217],[4,217],[4,217],[4,218],[4,218],[4,218],[4,218],[4,218],[4,219],[4,219],[4,219],[4,219],[4,219],[4,220],[4,220],[4,220],[4,220],[4,220],[4,221],[4,221],[4,221],[4,221],[4,221],[4,222],[4,222],[4,222],[4,222],[4,222],[4,223],[4,223],[4,223],[4,223],[4,223],[4,224],[4,224],[4,224],[4,224],[4,224],[4,225],[4,225],[4,225],[4,225],[4,225],[4,226],[4,226],[4,226],[4,226],[4,226],[4,227],[4,227],[4,227],[4,227],[4,227],[4,228],[4,228],[4,228],[4,228],[4,228],[4,229],[4,229],[4,229],[4,229],[4,229],[4,230],[4,230],[4,230],[4,230],[4,230],[4,231],[4,231],[4,231],[4,231],[4,231],[4,232],[4,232],[4,232],[4,232],[4,232],[4,233],[4,233],[4,233],[4,233],[4,233],[4,234],[4,234],[4,234],[4,234],[4,234],[4,235],[4,235],[4,235],[4,235],[4,235],[4,236],[4,236],[4,236],[4,236],[4,236],[4,237],[4,237],[4,237],[4,237],[4,237],[4,238],[4,238],[4,238],[4,238],[4,238],[4,239],[4,239],[4,239],[4,239],[4,239],[4,240],[4,240],[4,240],[4,240],[4,240],[4,241],[4,241],[4,241],[4,241],[4,241],[4,242],[4,242],[4,242],[4,242],[4,242],[4,243],[4,243],[4,243],[4,243],[4,243],[4,244],[4,244],[4,244],[4,244],[4,244],[4,245],[4,245],[4,245],[4,245],[4,245],[4,246],[4,246],[4,246],[4,246],[4,246],[4,247],[4,247],[4,247],[4,247],[4,247],[4,248],[4,248],[4,248],[4,248],[4,248],[4,249],[4,249],[4,249],[4,249],[4,249],[4,250],[4,250],[4,250],[4,250],[4,250],[4,251],[4,251],[4,251],[4,251],[4,251],[4,252],[4,252],[4,252],[4,252],[4,252],[4,253],[4,253],[4,253],[4,253],[4,253],[4,254],[4,254],[4,254],[4,254],[4,254],[4,255],[4,255],[4,255],[4,255],[4,255],[4,256],[4,256],[4,256],[4,256],[4,256],[4,257],[4,257],[4,257],[4,257],[4,257],[4,258],[4,258],[4,258],[4,258],[4,258],[4,259],[4,259],[4,259],[4,259],[4,259],[4,260],[4,260],[4,260],[4,260],[4,260],[4,261],[4,261],[4,261],[4,261],[4,261],[4,262],[4,262],[4,262],[4,262],[4,262],[4,263],[4,263],[4,263],[4,263],[4,263],[4,264],[4,264],[4,264],[4,264],[4,264],[4,265],[4,265],[4,265],[4,265],[4,265],[4,266],[4,266],[4,266],[4,266],[4,266],[4,267],[4,267],[4,267],[4,267],[4,267],[4,268],[4,268],[4,268],[4,268],[4,268],[4,269],[4,269],[4,269],[4,269],[4,269],[4,270],[4,270],[4,270],[4,270],[4,270],[4,271],[4,271],[4,271],[4,271],[4,271],[4,272],[4,272],[4,272],[4,272],[4,272],[4,273],[4,273],[4,273],[4,273],[4,273],[4,274],[4,274],[4,274],[4,274],[4,274],[4,275],[4,275],[4,275],[4,275],[4,275],[4,276],[4,276],[4,276],[4,276],[4,276],[4,277],[4,277],[4,277],[4,277],[4,277],[4,278],[4,278],[4,278],[4,278],[4,278],[4,279],[4,279],[4,279],[4,279],[4,279],[4,280],[4,280],[4,280],[4,280],[4,280],[4,281],[4,281],[4,281],[4,281],[4,281],[4,282],[4,282],[4,282],[4,282],[4,282],[4,283],[4,283],[4,283],[4,283],[4,283],[4,284],[4,284],[4,284],[4,284],[4,284],[4,285],[4,285],[4,285],[4,285],[4,285],[4,286],[4,286],[4,286],[4,286],[4,286],[4,287],[4,287],[4,287],[4,287],[4,287],[4,288],[4,288],[4,288],[4,288],[4,288],[4,289],[4,289],[4,289],[4,289],[4,289],[4,290],[4,290],[4,290],[4,290],[4,290],[4,291],[4,291],[4,291],[4,291],[4,291],[4,292],[4,292],[4,292],[4,292],[4,292],[4,293],[4,293],[4,293],[4,293],[4,293],[4,294],[4,294],[4,294],[4,294],[4,294],[4,295],[4,295],[4,295],[4,295],[4,295],[4,296],[4,296],[4,296],[4,296],[4,296],[4,297],[4,297],[4,297],[4,297],[4,297],[4,298],[4,298],[4,298],[4,298],[4,298],[4,299],[4,299],[4,299],[4,299],[4,299],[4,300],[4,300],[4,300],[4,300],[4,300],[4,301],[4,301],[4,301],[4,301],[4,301],[4,302],[4,302],[4,302],[4,302],[4,302],[4,303],[4,303],[4,303],[4,303],[4,303],[4,304],[4,304],[4,304],[4,304],[4,304],[4,305],[4,305],[4,305],[4,305],[4,305],[4,306],[4,306],[4,306],[4,306],[4,306],[4,307],[4,307],[4,307],[4,307],[4,307],[4,308],[4,308],[4,308],[4,308],[4,308],[4,309],[4,309],[4,309],[4,309],[4,309],[4,310],[4,310],[4,310],[4,310],[4,310],[4,311],[4,311],[4,311],[4,311],[4,311],[4,312],[4,312],[4,312],[4,312],[4,312],[4,313],[4,313],[4,313],[4,313],[4,313],[4,314],[4,314],[4,314],[4,314],[4,314],[4,315],[4,315],[4,315],[4,315],[4,315],[4,316],[4,316],[4,316],[4,316],[4,316],[4,317],[4,317],[4,317],[4,317],[4,317],[4,318],[4,318],[4,318],[4,318],[4,318],[4,319],[4,319],[4,319],[4,319],[4,319],[4,320],[4,320],[4,320],[4,320],[4,320],[4,321],[4,321],[4,321],[4,321],[4,321],[4,322],[4,322],[4,322],[4,322],[4,322],[4,323],[4,323],[4,323],[4,323],[4,323],[4,324],[4,324],[4,324],[4,324],[4,324],[4,325],[4,325],[4,325],[4,325],[4,325],[4,326],[4,326],[4,326],[4,326],[4,326],[4,327],[4,327],[4,327],[4,327],[4,327],[4,328],[4,328],[4,328],[4,328],[4,328],[4,329],[4,329],[4,329],[4,329],[4,329],[4,330],[4,330],[4,330],[4,330],[4,330],[4,331],[4,331],[4,331],[4,331],[4,331],[4,332],[4,332],[4,332],[4,332],[4,332],[4,333],[4,333],[4,333],[4,333],[4,333],[4,334],[4,334],[4,334],[4,334],[4,334],[4,335],[4,335],[4,335],[4,335],[4,335],[4,336],[4,336],[4,336],[4,336],[4,336],[4,337],[4,337],[4,337],[4,337],[4,337],[4,338],[4,338],[4,338],[4,338],[4,338],[4,339],[4,339],[4,339],[4,339],[4,339],[4,340],[4,340],[4,340],[4,340],[4,340],[4,341],[4,341],[4,341],[4,341],[4,341],[4,342],[4,342],[4,342],[4,342],[4,342],[4,343],[4,343],[4,343],[4,343],[4,343],[4,344],[4,344],[4,344],[4,344],[4,344],[4,345],[4,345],[4,345],[4,345],[4,345],[4,346],[4,346],[4,346],[4,346],[4,346],[4,347],[4,347],[4,347],[4,347],[4,347],[4,348],[4,348],[4,348],[4,348],[4,348],[4,349],[4,349],[4,349],[4,349],[4,349],[4,350],[4,350],[4,350],[4,350],[4,350],[4,351],[4,351],[4,351],[4,351],[4,351],[4,352],[4,352],[4,352],[4,352],[4,352],[4,353],[4,353],[4,353],[4,353],[4,353],[4,354],[4,354],[4,354],[4,354],[4,354],[4,355],[4,355],[4,355],[4,355],[4,355],[4,356],[4,356],[4,356],[4,356],[4,356],[4,357],[4,357],[4,357],[4,357],[4,357],[4,358],[4,358],[4,358],[4,358],[4,358],[4,359],[4,359],[4,359],[4,359],[4,359],[4,360],[4,360],[4,360],[4,360],[4,360],[4,361],[4,361],[4,361],[4,361],[4,361],[4,362],[4,362],[4,362],[4,362],[4,362],[4,363],[4,363],[4,363],[4,363],[4,363],[4,364],[4,364],[4,364],[4,364],[4,364],[4,365],[4,365],[4,365],[4,365],[4,365],[4,366],[4,366],[4,366],[4,366],[4,366],[4,367],[4,367],[4,367],[4,367],[4,367],[4,368],[4,368],[4,368],[4,368],[4,368],[4,369],[4,369],[4,369],[4,369],[4,369],[4,370],[4,370],[4,370],[4,370],[4,370],[4,371],[4,371],[4,371],[4,371],[4,371],[4,372],[4,372],[4,372],[4,372],[4,372],[4,373],[4,373],[4,373],[4,373],[4,373],[4,374],[4,374],[4,374],[4,374],[4,374],[4,375],[4,375],[4,375],[4,375],[4,375],[4,376],[4,376],[4,376],[4,376],[4,376],[4,377],[4,377],[4,377],[4,377],[4,377],[4,378],[4,378],[4,378],[4,378],[4,378],[4,379],[4,379],[4,379],[4,379],[4,379],[4,380],[4,380],[4,380],[4,380],[4,380],[4,381],[4,381],[4,381],[4,381],[4,381],[4,382],[4,382],[4,382],[4,382],[4,382],[4,383],[4,383],[4,383],[4,383],[4,383],[4,384],[4,384],[4,384],[4,384],[4,384],[4,385],[4,385],[4,385],[4,385],[4,385],[4,386],[4,386],[4,386],[4,386],[4,386],[4,387],[4,387],[4,387],[4,387],[4,387],[4,388],[4,388],[4,388],[4,388],[4,388],[4,389],[4,389],[4,389],[4,389],[4,389],[4,390],[4,390],[4,390],[4,390],[4,390],[4,391],[4,391],[4,391],[4,391],[4,391],[4,392],[4,392],[4,392],[4,392],[4,392],[4,393],[4,393],[4,393],[4,393],[4,393],[4,394],[4,394],[4,394],[4,394],[4,394],[4,395],[4,395],[4,395],[4,395],[4,395],[4,396],[4,396],[4,396],[4,396],[4,396],[4,397],[4,397],[4,397],[4,397],[4,397],[4,398],[4,398],[4,398],[4,398],[4,398],[4,399],[4,399],[4,399],[4,399],[4,399],[4,400],[4,400],[4,400],[4,400],[4,400],[4,401],[4,401],[4,401],[4,401],[4,401],[4,402],[4,402],[4,402],[4,402],[4,402],[4,403],[4,403],[4,403],[4,403],[4,403],[4,404],[4,404],[4,404],[4,404],[4,404],[4,405],[4,405],[4,405],[4,405],[4,405],[4,406],[4,406],[4,406],[4,406],[4,406],[4,407],[4,407],[4,407],[4,407],[4,407],[4,408],[4,408],[4,408],[4,408],[4,408],[4,409],[4,409],[4,409],[4,409],[4,409],[4,410],[4,410],[4,410],[4,410],[4,410],[4,411],[4,411],[4,411],[4,411],[4,411],[4,412],[4,412],[4,412],[4,412],[4,412],[4,413],[4,413],[4,413],[4,413],[4,413],[4,414],[4,414],[4,414],[4,414],[4,414],[4,415],[4,415],[4,415],[4,415],[4,415],[4,416],[4,416],[4,416],[4,416],[4,416],[4,417],[4,417],[4,417],[4,417],[4,417],[4,418],[4,418],[4,418],[4,418],[4,418],[4,419],[4,419],[4,419],[4,419],[4,419],[4,420],[4,420],[4,420],[4,420],[4,420],[4,421],[4,421],[4,421],[4,421],[4,421],[4,422],[4,422],[4,422],[4,422],[4,422],[4,423],[4,423],[4,423],[4,423],[4,423],[4,424],[4,424],[4,424],[4,424],[4,424],[4,425],[4,425],[4,425],[4,425],[4,425],[4,426],[4,426],[4,426],[4,426],[4,426],[4,427],[4,427],[4,427],[4,427],[4,427],[4,428],[4,428],[4,428],[4,428],[4,428],[4,429],[4,429],[4,429],[4,429],[4,429],[4,430],[4,430],[4,430],[4,430],[4,430],[4,431],[4,431],[4,431],[4,431],[4,431],[4,432],[4,432],[4,432],[4,432],[4,432],[4,433],[4,433],[4,433],[4,433],[4,433],[4,434],[4,434],[4,434],[4,434],[4,434],[4,435],[4,435],[4,435],[4,435],[4,435],[4,436],[4,436],[4,436],[4,436],[4,436],[4,437],[4,437],[4,437],[4,437],[4,437],[4,438],[4,438],[4,438],[4,438],[4,438],[4,439],[4,439],[4,439],[4,439],[4,439],[4,440],[4,440],[4,440],[4,440],[4,440],[4,441],[4,441],[4,441],[4,441],[4,441],[4,442],[4,442],[4,442],[4,442],[4,442],[4,443],[4,443],[4,443],[4,443],[4,443],[4,444],[4,444],[4,444],[4,444],[4,444],[4,445],[4,445],[4,445],[4,445],[4,445],[4,446],[4,446],[4,446],[4,446],[4,446],[4,447],[4,447],[4,447],[4,447],[4,447],[4,448],[4,448],[4,448],[4,448],[4,448],[4,449],[4,449],[4,449],[4,449],[4,449],[4,450],[4,450],[4,450],[4,450],[4,450],[4,451],[4,451],[4,451],[4,451],[4,451],[4,452],[4,452],[4,452],[4,452],[4,452],[4,453],[4,453],[4,453],[4,453],[4,453],[4,454],[4,454],[4,454],[4,454],[4,454],[4,455],[4,455],[4,455],[4,455],[4,455],[4,456],[4,456],[4,456],[4,456],[4,456],[4,457],[4,457],[4,457],[4,457],[4,457],[4,458],[4,458],[4,458],[4,458],[4,458],[4,459],[4,459],[4,459],[4,459],[4,459],[4,460],[4,460],[4,460],[4,460],[4,460],[4,461],[4,461],[4,461],[4,461],[4,461],[4,462],[4,462],[4,462],[4,462],[4,462],[4,463],[4,463],[4,463],[4,463],[4,463],[4,464],[4,464],[4,464],[4,464],[4,464],[4,465],[4,465],[4,465],[4,465],[4,465],[4,466],[4,466],[4,466],[4,466],[4,466],[4,467],[4,467],[4,467],[4,467],[4,467],[4,468],[4,468],[4,468],[4,468],[4,468],[4,469],[4,469],[4,469],[4,469],[4,469],[4,470],[4,470],[4,470],[4,470],[4,470],[4,471],[4,471],[4,471],[4,471],[4,471],[4,472],[4,472],[4,472],[4,472],[4,472],[4,473],[4,473],[4,473],[4,473],[4,473],[4,474],[4,474],[4,474],[4,474],[4,474],[4,475],[4,475],[4,475],[4,475],[4,475],[4,476],[4,476],[4,476],[4,476],[4,476],[4,477],[4,477],[4,477],[4,477],[4,477],[4,478],[4,478],[4,478],[4,478],[4,478],[4,479],[4,479],[4,479],[4,479],[4,479],[4,480],[4,480],[4,480],[4,480],[4,480],[4,481],[4,481],[4,481],[4,481],[4,481],[4,482],[4,482],[4,482],[4,482],[4,482],[4,483],[4,483],[4,483],[4,483],[4,483],[4,484],[4,484],[4,484],[4,484],[4,484],[4,485],[4,485],[4,485],[4,485],[4,485],[4,486],[4,486],[4,486],[4,486],[4,486],[4,487],[4,487],[4,487],[4,487],[4,487],[4,488],[4,488],[4,488],[4,488],[4,488],[4,489],[4,489],[4,489],[4,489],[4,489],[4,490],[4,490],[4,490],[4,490],[4,490],[4,491],[4,491],[4,491],[4,491],[4,491],[4,492],[4,492],[4,492],[4,492],[4,492],[4,493],[4,493],[4,493],[4,493],[4,493],[4,494],[4,494],[4,494],[4,494],[4,494],[4,495],[4,495],[4,495],[4,495],[4,495],[4,496],[4,496],[4,496],[4,496],[4,496],[4,497],[4,497],[4,497],[4,497],[4,497],[4,498],[4,498],[4,498],[4,498],[4,498],[4,499],[4,499],[4,499],[4,499],[4,499],[4,500],[4,500],[4,500],[4,500],[4,500],[5,2],[5,2],[5,2],[5,2],[5,2],[5,3],[5,3],[5,3],[5,3],[5,3],[5,4],[5,4],[5,4],[5,4],[5,4],[5,5],[5,5],[5,5],[5,5],[5,5],[5,6],[5,6],[5,6],[5,6],[5,6],[5,7],[5,7],[5,7],[5,7],[5,7],[5,8],[5,8],[5,8],[5,8],[5,8],[5,9],[5,9],[5,9],[5,9],[5,9],[5,10],[5,10],[5,10],[5,10],[5,10],[5,11],[5,11],[5,11],[5,11],[5,11],[5,12],[5,12],[5,12],[5,12],[5,12],[5,13],[5,13],[5,13],[5,13],[5,13],[5,14],[5,14],[5,14],[5,14],[5,14],[5,15],[5,15],[5,15],[5,15],[5,15],[5,16],[5,16],[5,16],[5,16],[5,16],[5,17],[5,17],[5,17],[5,17],[5,17],[5,18],[5,18],[5,18],[5,18],[5,18],[5,19],[5,19],[5,19],[5,19],[5,19],[5,20],[5,20],[5,20],[5,20],[5,20],[5,21],[5,21],[5,21],[5,21],[5,21],[5,22],[5,22],[5,22],[5,22],[5,22],[5,23],[5,23],[5,23],[5,23],[5,23],[5,24],[5,24],[5,24],[5,24],[5,24],[5,25],[5,25],[5,25],[5,25],[5,25],[5,26],[5,26],[5,26],[5,26],[5,26],[5,27],[5,27],[5,27],[5,27],[5,27],[5,28],[5,28],[5,28],[5,28],[5,28],[5,29],[5,29],[5,29],[5,29],[5,29],[5,30],[5,30],[5,30],[5,30],[5,30],[5,31],[5,31],[5,31],[5,31],[5,31],[5,32],[5,32],[5,32],[5,32],[5,32],[5,33],[5,33],[5,33],[5,33],[5,33],[5,34],[5,34],[5,34],[5,34],[5,34],[5,35],[5,35],[5,35],[5,35],[5,35],[5,36],[5,36],[5,36],[5,36],[5,36],[5,37],[5,37],[5,37],[5,37],[5,37],[5,38],[5,38],[5,38],[5,38],[5,38],[5,39],[5,39],[5,39],[5,39],[5,39],[5,40],[5,40],[5,40],[5,40],[5,40],[5,41],[5,41],[5,41],[5,41],[5,41],[5,42],[5,42],[5,42],[5,42],[5,42],[5,43],[5,43],[5,43],[5,43],[5,43],[5,44],[5,44],[5,44],[5,44],[5,44],[5,45],[5,45],[5,45],[5,45],[5,45],[5,46],[5,46],[5,46],[5,46],[5,46],[5,47],[5,47],[5,47],[5,47],[5,47],[5,48],[5,48],[5,48],[5,48],[5,48],[5,49],[5,49],[5,49],[5,49],[5,49],[5,50],[5,50],[5,50],[5,50],[5,50],[5,51],[5,51],[5,51],[5,51],[5,51],[5,52],[5,52],[5,52],[5,52],[5,52],[5,53],[5,53],[5,53],[5,53],[5,53],[5,54],[5,54],[5,54],[5,54],[5,54],[5,55],[5,55],[5,55],[5,55],[5,55],[5,56],[5,56],[5,56],[5,56],[5,56],[5,57],[5,57],[5,57],[5,57],[5,57],[5,58],[5,58],[5,58],[5,58],[5,58],[5,59],[5,59],[5,59],[5,59],[5,59],[5,60],[5,60],[5,60],[5,60],[5,60],[5,61],[5,61],[5,61],[5,61],[5,61],[5,62],[5,62],[5,62],[5,62],[5,62],[5,63],[5,63],[5,63],[5,63],[5,63],[5,64],[5,64],[5,64],[5,64],[5,64],[5,65],[5,65],[5,65],[5,65],[5,65],[5,66],[5,66],[5,66],[5,66],[5,66],[5,67],[5,67],[5,67],[5,67],[5,67],[5,68],[5,68],[5,68],[5,68],[5,68],[5,69],[5,69],[5,69],[5,69],[5,69],[5,70],[5,70],[5,70],[5,70],[5,70],[5,71],[5,71],[5,71],[5,71],[5,71],[5,72],[5,72],[5,72],[5,72],[5,72],[5,73],[5,73],[5,73],[5,73],[5,73],[5,74],[5,74],[5,74],[5,74],[5,74],[5,75],[5,75],[5,75],[5,75],[5,75],[5,76],[5,76],[5,76],[5,76],[5,76],[5,77],[5,77],[5,77],[5,77],[5,77],[5,78],[5,78],[5,78],[5,78],[5,78],[5,79],[5,79],[5,79],[5,79],[5,79],[5,80],[5,80],[5,80],[5,80],[5,80],[5,81],[5,81],[5,81],[5,81],[5,81],[5,82],[5,82],[5,82],[5,82],[5,82],[5,83],[5,83],[5,83],[5,83],[5,83],[5,84],[5,84],[5,84],[5,84],[5,84],[5,85],[5,85],[5,85],[5,85],[5,85],[5,86],[5,86],[5,86],[5,86],[5,86],[5,87],[5,87],[5,87],[5,87],[5,87],[5,88],[5,88],[5,88],[5,88],[5,88],[5,89],[5,89],[5,89],[5,89],[5,89],[5,90],[5,90],[5,90],[5,90],[5,90],[5,91],[5,91],[5,91],[5,91],[5,91],[5,92],[5,92],[5,92],[5,92],[5,92],[5,93],[5,93],[5,93],[5,93],[5,93],[5,94],[5,94],[5,94],[5,94],[5,94],[5,95],[5,95],[5,95],[5,95],[5,95],[5,96],[5,96],[5,96],[5,96],[5,96],[5,97],[5,97],[5,97],[5,97],[5,97],[5,98],[5,98],[5,98],[5,98],[5,98],[5,99],[5,99],[5,99],[5,99],[5,99],[5,100],[5,100],[5,100],[5,100],[5,100],[5,101],[5,101],[5,101],[5,101],[5,101],[5,102],[5,102],[5,102],[5,102],[5,102],[5,103],[5,103],[5,103],[5,103],[5,103],[5,104],[5,104],[5,104],[5,104],[5,104],[5,105],[5,105],[5,105],[5,105],[5,105],[5,106],[5,106],[5,106],[5,106],[5,106],[5,107],[5,107],[5,107],[5,107],[5,107],[5,108],[5,108],[5,108],[5,108],[5,108],[5,109],[5,109],[5,109],[5,109],[5,109],[5,110],[5,110],[5,110],[5,110],[5,110],[5,111],[5,111],[5,111],[5,111],[5,111],[5,112],[5,112],[5,112],[5,112],[5,112],[5,113],[5,113],[5,113],[5,113],[5,113],[5,114],[5,114],[5,114],[5,114],[5,114],[5,115],[5,115],[5,115],[5,115],[5,115],[5,116],[5,116],[5,116],[5,116],[5,116],[5,117],[5,117],[5,117],[5,117],[5,117],[5,118],[5,118],[5,118],[5,118],[5,118],[5,119],[5,119],[5,119],[5,119],[5,119],[5,120],[5,120],[5,120],[5,120],[5,120],[5,121],[5,121],[5,121],[5,121],[5,121],[5,122],[5,122],[5,122],[5,122],[5,122],[5,123],[5,123],[5,123],[5,123],[5,123],[5,124],[5,124],[5,124],[5,124],[5,124],[5,125],[5,125],[5,125],[5,125],[5,125],[5,126],[5,126],[5,126],[5,126],[5,126],[5,127],[5,127],[5,127],[5,127],[5,127],[5,128],[5,128],[5,128],[5,128],[5,128],[5,129],[5,129],[5,129],[5,129],[5,129],[5,130],[5,130],[5,130],[5,130],[5,130],[5,131],[5,131],[5,131],[5,131],[5,131],[5,132],[5,132],[5,132],[5,132],[5,132],[5,133],[5,133],[5,133],[5,133],[5,133],[5,134],[5,134],[5,134],[5,134],[5,134],[5,135],[5,135],[5,135],[5,135],[5,135],[5,136],[5,136],[5,136],[5,136],[5,136],[5,137],[5,137],[5,137],[5,137],[5,137],[5,138],[5,138],[5,138],[5,138],[5,138],[5,139],[5,139],[5,139],[5,139],[5,139],[5,140],[5,140],[5,140],[5,140],[5,140],[5,141],[5,141],[5,141],[5,141],[5,141],[5,142],[5,142],[5,142],[5,142],[5,142],[5,143],[5,143],[5,143],[5,143],[5,143],[5,144],[5,144],[5,144],[5,144],[5,144],[5,145],[5,145],[5,145],[5,145],[5,145],[5,146],[5,146],[5,146],[5,146],[5,146],[5,147],[5,147],[5,147],[5,147],[5,147],[5,148],[5,148],[5,148],[5,148],[5,148],[5,149],[5,149],[5,149],[5,149],[5,149],[5,150],[5,150],[5,150],[5,150],[5,150],[5,151],[5,151],[5,151],[5,151],[5,151],[5,152],[5,152],[5,152],[5,152],[5,152],[5,153],[5,153],[5,153],[5,153],[5,153],[5,154],[5,154],[5,154],[5,154],[5,154],[5,155],[5,155],[5,155],[5,155],[5,155],[5,156],[5,156],[5,156],[5,156],[5,156],[5,157],[5,157],[5,157],[5,157],[5,157],[5,158],[5,158],[5,158],[5,158],[5,158],[5,159],[5,159],[5,159],[5,159],[5,159],[5,160],[5,160],[5,160],[5,160],[5,160],[5,161],[5,161],[5,161],[5,161],[5,161],[5,162],[5,162],[5,162],[5,162],[5,162],[5,163],[5,163],[5,163],[5,163],[5,163],[5,164],[5,164],[5,164],[5,164],[5,164],[5,165],[5,165],[5,165],[5,165],[5,165],[5,166],[5,166],[5,166],[5,166],[5,166],[5,167],[5,167],[5,167],[5,167],[5,167],[5,168],[5,168],[5,168],[5,168],[5,168],[5,169],[5,169],[5,169],[5,169],[5,169],[5,170],[5,170],[5,170],[5,170],[5,170],[5,171],[5,171],[5,171],[5,171],[5,171],[5,172],[5,172],[5,172],[5,172],[5,172],[5,173],[5,173],[5,173],[5,173],[5,173],[5,174],[5,174],[5,174],[5,174],[5,174],[5,175],[5,175],[5,175],[5,175],[5,175],[5,176],[5,176],[5,176],[5,176],[5,176],[5,177],[5,177],[5,177],[5,177],[5,177],[5,178],[5,178],[5,178],[5,178],[5,178],[5,179],[5,179],[5,179],[5,179],[5,179],[5,180],[5,180],[5,180],[5,180],[5,180],[5,181],[5,181],[5,181],[5,181],[5,181],[5,182],[5,182],[5,182],[5,182],[5,182],[5,183],[5,183],[5,183],[5,183],[5,183],[5,184],[5,184],[5,184],[5,184],[5,184],[5,185],[5,185],[5,185],[5,185],[5,185],[5,186],[5,186],[5,186],[5,186],[5,186],[5,187],[5,187],[5,187],[5,187],[5,187],[5,188],[5,188],[5,188],[5,188],[5,188],[5,189],[5,189],[5,189],[5,189],[5,189],[5,190],[5,190],[5,190],[5,190],[5,190],[5,191],[5,191],[5,191],[5,191],[5,191],[5,192],[5,192],[5,192],[5,192],[5,192],[5,193],[5,193],[5,193],[5,193],[5,193],[5,194],[5,194],[5,194],[5,194],[5,194],[5,195],[5,195],[5,195],[5,195],[5,195],[5,196],[5,196],[5,196],[5,196],[5,196],[5,197],[5,197],[5,197],[5,197],[5,197],[5,198],[5,198],[5,198],[5,198],[5,198],[5,199],[5,199],[5,199],[5,199],[5,199],[5,200],[5,200],[5,200],[5,200],[5,200],[5,201],[5,201],[5,201],[5,201],[5,201],[5,202],[5,202],[5,202],[5,202],[5,202],[5,203],[5,203],[5,203],[5,203],[5,203],[5,204],[5,204],[5,204],[5,204],[5,204],[5,205],[5,205],[5,205],[5,205],[5,205],[5,206],[5,206],[5,206],[5,206],[5,206],[5,207],[5,207],[5,207],[5,207],[5,207],[5,208],[5,208],[5,208],[5,208],[5,208],[5,209],[5,209],[5,209],[5,209],[5,209],[5,210],[5,210],[5,210],[5,210],[5,210],[5,211],[5,211],[5,211],[5,211],[5,211],[5,212],[5,212],[5,212],[5,212],[5,212],[5,213],[5,213],[5,213],[5,213],[5,213],[5,214],[5,214],[5,214],[5,214],[5,214],[5,215],[5,215],[5,215],[5,215],[5,215],[5,216],[5,216],[5,216],[5,216],[5,216],[5,217],[5,217],[5,217],[5,217],[5,217],[5,218],[5,218],[5,218],[5,218],[5,218],[5,219],[5,219],[5,219],[5,219],[5,219],[5,220],[5,220],[5,220],[5,220],[5,220],[5,221],[5,221],[5,221],[5,221],[5,221],[5,222],[5,222],[5,222],[5,222],[5,222],[5,223],[5,223],[5,223],[5,223],[5,223],[5,224],[5,224],[5,224],[5,224],[5,224],[5,225],[5,225],[5,225],[5,225],[5,225],[5,226],[5,226],[5,226],[5,226],[5,226],[5,227],[5,227],[5,227],[5,227],[5,227],[5,228],[5,228],[5,228],[5,228],[5,228],[5,229],[5,229],[5,229],[5,229],[5,229],[5,230],[5,230],[5,230],[5,230],[5,230],[5,231],[5,231],[5,231],[5,231],[5,231],[5,232],[5,232],[5,232],[5,232],[5,232],[5,233],[5,233],[5,233],[5,233],[5,233],[5,234],[5,234],[5,234],[5,234],[5,234],[5,235],[5,235],[5,235],[5,235],[5,235],[5,236],[5,236],[5,236],[5,236],[5,236],[5,237],[5,237],[5,237],[5,237],[5,237],[5,238],[5,238],[5,238],[5,238],[5,238],[5,239],[5,239],[5,239],[5,239],[5,239],[5,240],[5,240],[5,240],[5,240],[5,240],[5,241],[5,241],[5,241],[5,241],[5,241],[5,242],[5,242],[5,242],[5,242],[5,242],[5,243],[5,243],[5,243],[5,243],[5,243],[5,244],[5,244],[5,244],[5,244],[5,244],[5,245],[5,245],[5,245],[5,245],[5,245],[5,246],[5,246],[5,246],[5,246],[5,246],[5,247],[5,247],[5,247],[5,247],[5,247],[5,248],[5,248],[5,248],[5,248],[5,248],[5,249],[5,249],[5,249],[5,249],[5,249],[5,250],[5,250],[5,250],[5,250],[5,250],[5,251],[5,251],[5,251],[5,251],[5,251],[5,252],[5,252],[5,252],[5,252],[5,252],[5,253],[5,253],[5,253],[5,253],[5,253],[5,254],[5,254],[5,254],[5,254],[5,254],[5,255],[5,255],[5,255],[5,255],[5,255],[5,256],[5,256],[5,256],[5,256],[5,256],[5,257],[5,257],[5,257],[5,257],[5,257],[5,258],[5,258],[5,258],[5,258],[5,258],[5,259],[5,259],[5,259],[5,259],[5,259],[5,260],[5,260],[5,260],[5,260],[5,260],[5,261],[5,261],[5,261],[5,261],[5,261],[5,262],[5,262],[5,262],[5,262],[5,262],[5,263],[5,263],[5,263],[5,263],[5,263],[5,264],[5,264],[5,264],[5,264],[5,264],[5,265],[5,265],[5,265],[5,265],[5,265],[5,266],[5,266],[5,266],[5,266],[5,266],[5,267],[5,267],[5,267],[5,267],[5,267],[5,268],[5,268],[5,268],[5,268],[5,268],[5,269],[5,269],[5,269],[5,269],[5,269],[5,270],[5,270],[5,270],[5,270],[5,270],[5,271],[5,271],[5,271],[5,271],[5,271],[5,272],[5,272],[5,272],[5,272],[5,272],[5,273],[5,273],[5,273],[5,273],[5,273],[5,274],[5,274],[5,274],[5,274],[5,274],[5,275],[5,275],[5,275],[5,275],[5,275],[5,276],[5,276],[5,276],[5,276],[5,276],[5,277],[5,277],[5,277],[5,277],[5,277],[5,278],[5,278],[5,278],[5,278],[5,278],[5,279],[5,279],[5,279],[5,279],[5,279],[5,280],[5,280],[5,280],[5,280],[5,280],[5,281],[5,281],[5,281],[5,281],[5,281],[5,282],[5,282],[5,282],[5,282],[5,282],[5,283],[5,283],[5,283],[5,283],[5,283],[5,284],[5,284],[5,284],[5,284],[5,284],[5,285],[5,285],[5,285],[5,285],[5,285],[5,286],[5,286],[5,286],[5,286],[5,286],[5,287],[5,287],[5,287],[5,287],[5,287],[5,288],[5,288],[5,288],[5,288],[5,288],[5,289],[5,289],[5,289],[5,289],[5,289],[5,290],[5,290],[5,290],[5,290],[5,290],[5,291],[5,291],[5,291],[5,291],[5,291],[5,292],[5,292],[5,292],[5,292],[5,292],[5,293],[5,293],[5,293],[5,293],[5,293],[5,294],[5,294],[5,294],[5,294],[5,294],[5,295],[5,295],[5,295],[5,295],[5,295],[5,296],[5,296],[5,296],[5,296],[5,296],[5,297],[5,297],[5,297],[5,297],[5,297],[5,298],[5,298],[5,298],[5,298],[5,298],[5,299],[5,299],[5,299],[5,299],[5,299],[5,300],[5,300],[5,300],[5,300],[5,300],[5,301],[5,301],[5,301],[5,301],[5,301],[5,302],[5,302],[5,302],[5,302],[5,302],[5,303],[5,303],[5,303],[5,303],[5,303],[5,304],[5,304],[5,304],[5,304],[5,304],[5,305],[5,305],[5,305],[5,305],[5,305],[5,306],[5,306],[5,306],[5,306],[5,306],[5,307],[5,307],[5,307],[5,307],[5,307],[5,308],[5,308],[5,308],[5,308],[5,308],[5,309],[5,309],[5,309],[5,309],[5,309],[5,310],[5,310],[5,310],[5,310],[5,310],[5,311],[5,311],[5,311],[5,311],[5,311],[5,312],[5,312],[5,312],[5,312],[5,312],[5,313],[5,313],[5,313],[5,313],[5,313],[5,314],[5,314],[5,314],[5,314],[5,314],[5,315],[5,315],[5,315],[5,315],[5,315],[5,316],[5,316],[5,316],[5,316],[5,316],[5,317],[5,317],[5,317],[5,317],[5,317],[5,318],[5,318],[5,318],[5,318],[5,318],[5,319],[5,319],[5,319],[5,319],[5,319],[5,320],[5,320],[5,320],[5,320],[5,320],[5,321],[5,321],[5,321],[5,321],[5,321],[5,322],[5,322],[5,322],[5,322],[5,322],[5,323],[5,323],[5,323],[5,323],[5,323],[5,324],[5,324],[5,324],[5,324],[5,324],[5,325],[5,325],[5,325],[5,325],[5,325],[5,326],[5,326],[5,326],[5,326],[5,326],[5,327],[5,327],[5,327],[5,327],[5,327],[5,328],[5,328],[5,328],[5,328],[5,328],[5,329],[5,329],[5,329],[5,329],[5,329],[5,330],[5,330],[5,330],[5,330],[5,330],[5,331],[5,331],[5,331],[5,331],[5,331],[5,332],[5,332],[5,332],[5,332],[5,332],[5,333],[5,333],[5,333],[5,333],[5,333],[5,334],[5,334],[5,334],[5,334],[5,334],[5,335],[5,335],[5,335],[5,335],[5,335],[5,336],[5,336],[5,336],[5,336],[5,336],[5,337],[5,337],[5,337],[5,337],[5,337],[5,338],[5,338],[5,338],[5,338],[5,338],[5,339],[5,339],[5,339],[5,339],[5,339],[5,340],[5,340],[5,340],[5,340],[5,340],[5,341],[5,341],[5,341],[5,341],[5,341],[5,342],[5,342],[5,342],[5,342],[5,342],[5,343],[5,343],[5,343],[5,343],[5,343],[5,344],[5,344],[5,344],[5,344],[5,344],[5,345],[5,345],[5,345],[5,345],[5,345],[5,346],[5,346],[5,346],[5,346],[5,346],[5,347],[5,347],[5,347],[5,347],[5,347],[5,348],[5,348],[5,348],[5,348],[5,348],[5,349],[5,349],[5,349],[5,349],[5,349],[5,350],[5,350],[5,350],[5,350],[5,350],[5,351],[5,351],[5,351],[5,351],[5,351],[5,352],[5,352],[5,352],[5,352],[5,352],[5,353],[5,353],[5,353],[5,353],[5,353],[5,354],[5,354],[5,354],[5,354],[5,354],[5,355],[5,355],[5,355],[5,355],[5,355],[5,356],[5,356],[5,356],[5,356],[5,356],[5,357],[5,357],[5,357],[5,357],[5,357],[5,358],[5,358],[5,358],[5,358],[5,358],[5,359],[5,359],[5,359],[5,359],[5,359],[5,360],[5,360],[5,360],[5,360],[5,360],[5,361],[5,361],[5,361],[5,361],[5,361],[5,362],[5,362],[5,362],[5,362],[5,362],[5,363],[5,363],[5,363],[5,363],[5,363],[5,364],[5,364],[5,364],[5,364],[5,364],[5,365],[5,365],[5,365],[5,365],[5,365],[5,366],[5,366],[5,366],[5,366],[5,366],[5,367],[5,367],[5,367],[5,367],[5,367],[5,368],[5,368],[5,368],[5,368],[5,368],[5,369],[5,369],[5,369],[5,369],[5,369],[5,370],[5,370],[5,370],[5,370],[5,370],[5,371],[5,371],[5,371],[5,371],[5,371],[5,372],[5,372],[5,372],[5,372],[5,372],[5,373],[5,373],[5,373],[5,373],[5,373],[5,374],[5,374],[5,374],[5,374],[5,374],[5,375],[5,375],[5,375],[5,375],[5,375],[5,376],[5,376],[5,376],[5,376],[5,376],[5,377],[5,377],[5,377],[5,377],[5,377],[5,378],[5,378],[5,378],[5,378],[5,378],[5,379],[5,379],[5,379],[5,379],[5,379],[5,380],[5,380],[5,380],[5,380],[5,380],[5,381],[5,381],[5,381],[5,381],[5,381],[5,382],[5,382],[5,382],[5,382],[5,382],[5,383],[5,383],[5,383],[5,383],[5,383],[5,384],[5,384],[5,384],[5,384],[5,384],[5,385],[5,385],[5,385],[5,385],[5,385],[5,386],[5,386],[5,386],[5,386],[5,386],[5,387],[5,387],[5,387],[5,387],[5,387],[5,388],[5,388],[5,388],[5,388],[5,388],[5,389],[5,389],[5,389],[5,389],[5,389],[5,390],[5,390],[5,390],[5,390],[5,390],[5,391],[5,391],[5,391],[5,391],[5,391],[5,392],[5,392],[5,392],[5,392],[5,392],[5,393],[5,393],[5,393],[5,393],[5,393],[5,394],[5,394],[5,394],[5,394],[5,394],[5,395],[5,395],[5,395],[5,395],[5,395],[5,396],[5,396],[5,396],[5,396],[5,396],[5,397],[5,397],[5,397],[5,397],[5,397],[5,398],[5,398],[5,398],[5,398],[5,398],[5,399],[5,399],[5,399],[5,399],[5,399],[5,400],[5,400],[5,400],[5,400],[5,400],[5,401],[5,401],[5,401],[5,401],[5,401],[5,402],[5,402],[5,402],[5,402],[5,402],[5,403],[5,403],[5,403],[5,403],[5,403],[5,404],[5,404],[5,404],[5,404],[5,404],[5,405],[5,405],[5,405],[5,405],[5,405],[5,406],[5,406],[5,406],[5,406],[5,406],[5,407],[5,407],[5,407],[5,407],[5,407],[5,408],[5,408],[5,408],[5,408],[5,408],[5,409],[5,409],[5,409],[5,409],[5,409],[5,410],[5,410],[5,410],[5,410],[5,410],[5,411],[5,411],[5,411],[5,411],[5,411],[5,412],[5,412],[5,412],[5,412],[5,412],[5,413],[5,413],[5,413],[5,413],[5,413],[5,414],[5,414],[5,414],[5,414],[5,414],[5,415],[5,415],[5,415],[5,415],[5,415],[5,416],[5,416],[5,416],[5,416],[5,416],[5,417],[5,417],[5,417],[5,417],[5,417],[5,418],[5,418],[5,418],[5,418],[5,418],[5,419],[5,419],[5,419],[5,419],[5,419],[5,420],[5,420],[5,420],[5,420],[5,420],[5,421],[5,421],[5,421],[5,421],[5,421],[5,422],[5,422],[5,422],[5,422],[5,422],[5,423],[5,423],[5,423],[5,423],[5,423],[5,424],[5,424],[5,424],[5,424],[5,424],[5,425],[5,425],[5,425],[5,425],[5,425],[5,426],[5,426],[5,426],[5,426],[5,426],[5,427],[5,427],[5,427],[5,427],[5,427],[5,428],[5,428],[5,428],[5,428],[5,428],[5,429],[5,429],[5,429],[5,429],[5,429],[5,430],[5,430],[5,430],[5,430],[5,430],[5,431],[5,431],[5,431],[5,431],[5,431],[5,432],[5,432],[5,432],[5,432],[5,432],[5,433],[5,433],[5,433],[5,433],[5,433],[5,434],[5,434],[5,434],[5,434],[5,434],[5,435],[5,435],[5,435],[5,435],[5,435],[5,436],[5,436],[5,436],[5,436],[5,436],[5,437],[5,437],[5,437],[5,437],[5,437],[5,438],[5,438],[5,438],[5,438],[5,438],[5,439],[5,439],[5,439],[5,439],[5,439],[5,440],[5,440],[5,440],[5,440],[5,440],[5,441],[5,441],[5,441],[5,441],[5,441],[5,442],[5,442],[5,442],[5,442],[5,442],[5,443],[5,443],[5,443],[5,443],[5,443],[5,444],[5,444],[5,444],[5,444],[5,444],[5,445],[5,445],[5,445],[5,445],[5,445],[5,446],[5,446],[5,446],[5,446],[5,446],[5,447],[5,447],[5,447],[5,447],[5,447],[5,448],[5,448],[5,448],[5,448],[5,448],[5,449],[5,449],[5,449],[5,449],[5,449],[5,450],[5,450],[5,450],[5,450],[5,450],[5,451],[5,451],[5,451],[5,451],[5,451],[5,452],[5,452],[5,452],[5,452],[5,452],[5,453],[5,453],[5,453],[5,453],[5,453],[5,454],[5,454],[5,454],[5,454],[5,454],[5,455],[5,455],[5,455],[5,455],[5,455],[5,456],[5,456],[5,456],[5,456],[5,456],[5,457],[5,457],[5,457],[5,457],[5,457],[5,458],[5,458],[5,458],[5,458],[5,458],[5,459],[5,459],[5,459],[5,459],[5,459],[5,460],[5,460],[5,460],[5,460],[5,460],[5,461],[5,461],[5,461],[5,461],[5,461],[5,462],[5,462],[5,462],[5,462],[5,462],[5,463],[5,463],[5,463],[5,463],[5,463],[5,464],[5,464],[5,464],[5,464],[5,464],[5,465],[5,465],[5,465],[5,465],[5,465],[5,466],[5,466],[5,466],[5,466],[5,466],[5,467],[5,467],[5,467],[5,467],[5,467],[5,468],[5,468],[5,468],[5,468],[5,468],[5,469],[5,469],[5,469],[5,469],[5,469],[5,470],[5,470],[5,470],[5,470],[5,470],[5,471],[5,471],[5,471],[5,471],[5,471],[5,472],[5,472],[5,472],[5,472],[5,472],[5,473],[5,473],[5,473],[5,473],[5,473],[5,474],[5,474],[5,474],[5,474],[5,474],[5,475],[5,475],[5,475],[5,475],[5,475],[5,476],[5,476],[5,476],[5,476],[5,476],[5,477],[5,477],[5,477],[5,477],[5,477],[5,478],[5,478],[5,478],[5,478],[5,478],[5,479],[5,479],[5,479],[5,479],[5,479],[5,480],[5,480],[5,480],[5,480],[5,480],[5,481],[5,481],[5,481],[5,481],[5,481],[5,482],[5,482],[5,482],[5,482],[5,482],[5,483],[5,483],[5,483],[5,483],[5,483],[5,484],[5,484],[5,484],[5,484],[5,484],[5,485],[5,485],[5,485],[5,485],[5,485],[5,486],[5,486],[5,486],[5,486],[5,486],[5,487],[5,487],[5,487],[5,487],[5,487],[5,488],[5,488],[5,488],[5,488],[5,488],[5,489],[5,489],[5,489],[5,489],[5,489],[5,490],[5,490],[5,490],[5,490],[5,490],[5,491],[5,491],[5,491],[5,491],[5,491],[5,492],[5,492],[5,492],[5,492],[5,492],[5,493],[5,493],[5,493],[5,493],[5,493],[5,494],[5,494],[5,494],[5,494],[5,494],[5,495],[5,495],[5,495],[5,495],[5,495],[5,496],[5,496],[5,496],[5,496],[5,496],[5,497],[5,497],[5,497],[5,497],[5,497],[5,498],[5,498],[5,498],[5,498],[5,498],[5,499],[5,499],[5,499],[5,499],[5,499],[5,500],[5,500],[5,500],[5,500],[5,500],[6,2],[6,2],[6,2],[6,2],[6,2],[6,3],[6,3],[6,3],[6,3],[6,3],[6,4],[6,4],[6,4],[6,4],[6,4],[6,5],[6,5],[6,5],[6,5],[6,5],[6,6],[6,6],[6,6],[6,6],[6,6],[6,7],[6,7],[6,7],[6,7],[6,7],[6,8],[6,8],[6,8],[6,8],[6,8],[6,9],[6,9],[6,9],[6,9],[6,9],[6,10],[6,10],[6,10],[6,10],[6,10],[6,11],[6,11],[6,11],[6,11],[6,11],[6,12],[6,12],[6,12],[6,12],[6,12],[6,13],[6,13],[6,13],[6,13],[6,13],[6,14],[6,14],[6,14],[6,14],[6,14],[6,15],[6,15],[6,15],[6,15],[6,15],[6,16],[6,16],[6,16],[6,16],[6,16],[6,17],[6,17],[6,17],[6,17],[6,17],[6,18],[6,18],[6,18],[6,18],[6,18],[6,19],[6,19],[6,19],[6,19],[6,19],[6,20],[6,20],[6,20],[6,20],[6,20],[6,21],[6,21],[6,21],[6,21],[6,21],[6,22],[6,22],[6,22],[6,22],[6,22],[6,23],[6,23],[6,23],[6,23],[6,23],[6,24],[6,24],[6,24],[6,24],[6,24],[6,25],[6,25],[6,25],[6,25],[6,25],[6,26],[6,26],[6,26],[6,26],[6,26],[6,27],[6,27],[6,27],[6,27],[6,27],[6,28],[6,28],[6,28],[6,28],[6,28],[6,29],[6,29],[6,29],[6,29],[6,29],[6,30],[6,30],[6,30],[6,30],[6,30],[6,31],[6,31],[6,31],[6,31],[6,31],[6,32],[6,32],[6,32],[6,32],[6,32],[6,33],[6,33],[6,33],[6,33],[6,33],[6,34],[6,34],[6,34],[6,34],[6,34],[6,35],[6,35],[6,35],[6,35],[6,35],[6,36],[6,36],[6,36],[6,36],[6,36],[6,37],[6,37],[6,37],[6,37],[6,37],[6,38],[6,38],[6,38],[6,38],[6,38],[6,39],[6,39],[6,39],[6,39],[6,39],[6,40],[6,40],[6,40],[6,40],[6,40],[6,41],[6,41],[6,41],[6,41],[6,41],[6,42],[6,42],[6,42],[6,42],[6,42],[6,43],[6,43],[6,43],[6,43],[6,43],[6,44],[6,44],[6,44],[6,44],[6,44],[6,45],[6,45],[6,45],[6,45],[6,45],[6,46],[6,46],[6,46],[6,46],[6,46],[6,47],[6,47],[6,47],[6,47],[6,47],[6,48],[6,48],[6,48],[6,48],[6,48],[6,49],[6,49],[6,49],[6,49],[6,49],[6,50],[6,50],[6,50],[6,50],[6,50],[6,51],[6,51],[6,51],[6,51],[6,51],[6,52],[6,52],[6,52],[6,52],[6,52],[6,53],[6,53],[6,53],[6,53],[6,53],[6,54],[6,54],[6,54],[6,54],[6,54],[6,55],[6,55],[6,55],[6,55],[6,55],[6,56],[6,56],[6,56],[6,56],[6,56],[6,57],[6,57],[6,57],[6,57],[6,57],[6,58],[6,58],[6,58],[6,58],[6,58],[6,59],[6,59],[6,59],[6,59],[6,59],[6,60],[6,60],[6,60],[6,60],[6,60],[6,61],[6,61],[6,61],[6,61],[6,61],[6,62],[6,62],[6,62],[6,62],[6,62],[6,63],[6,63],[6,63],[6,63],[6,63],[6,64],[6,64],[6,64],[6,64],[6,64],[6,65],[6,65],[6,65],[6,65],[6,65],[6,66],[6,66],[6,66],[6,66],[6,66],[6,67],[6,67],[6,67],[6,67],[6,67],[6,68],[6,68],[6,68],[6,68],[6,68],[6,69],[6,69],[6,69],[6,69],[6,69],[6,70],[6,70],[6,70],[6,70],[6,70],[6,71],[6,71],[6,71],[6,71],[6,71],[6,72],[6,72],[6,72],[6,72],[6,72],[6,73],[6,73],[6,73],[6,73],[6,73],[6,74],[6,74],[6,74],[6,74],[6,74],[6,75],[6,75],[6,75],[6,75],[6,75],[6,76],[6,76],[6,76],[6,76],[6,76],[6,77],[6,77],[6,77],[6,77],[6,77],[6,78],[6,78],[6,78],[6,78],[6,78],[6,79],[6,79],[6,79],[6,79],[6,79],[6,80],[6,80],[6,80],[6,80],[6,80],[6,81],[6,81],[6,81],[6,81],[6,81],[6,82],[6,82],[6,82],[6,82],[6,82],[6,83],[6,83],[6,83],[6,83],[6,83],[6,84],[6,84],[6,84],[6,84],[6,84],[6,85],[6,85],[6,85],[6,85],[6,85],[6,86],[6,86],[6,86],[6,86],[6,86],[6,87],[6,87],[6,87],[6,87],[6,87],[6,88],[6,88],[6,88],[6,88],[6,88],[6,89],[6,89],[6,89],[6,89],[6,89],[6,90],[6,90],[6,90],[6,90],[6,90],[6,91],[6,91],[6,91],[6,91],[6,91],[6,92],[6,92],[6,92],[6,92],[6,92],[6,93],[6,93],[6,93],[6,93],[6,93],[6,94],[6,94],[6,94],[6,94],[6,94],[6,95],[6,95],[6,95],[6,95],[6,95],[6,96],[6,96],[6,96],[6,96],[6,96],[6,97],[6,97],[6,97],[6,97],[6,97],[6,98],[6,98],[6,98],[6,98],[6,98],[6,99],[6,99],[6,99],[6,99],[6,99],[6,100],[6,100],[6,100],[6,100],[6,100],[6,101],[6,101],[6,101],[6,101],[6,101],[6,102],[6,102],[6,102],[6,102],[6,102],[6,103],[6,103],[6,103],[6,103],[6,103],[6,104],[6,104],[6,104],[6,104],[6,104],[6,105],[6,105],[6,105],[6,105],[6,105],[6,106],[6,106],[6,106],[6,106],[6,106],[6,107],[6,107],[6,107],[6,107],[6,107],[6,108],[6,108],[6,108],[6,108],[6,108],[6,109],[6,109],[6,109],[6,109],[6,109],[6,110],[6,110],[6,110],[6,110],[6,110],[6,111],[6,111],[6,111],[6,111],[6,111],[6,112],[6,112],[6,112],[6,112],[6,112],[6,113],[6,113],[6,113],[6,113],[6,113],[6,114],[6,114],[6,114],[6,114],[6,114],[6,115],[6,115],[6,115],[6,115],[6,115],[6,116],[6,116],[6,116],[6,116],[6,116],[6,117],[6,117],[6,117],[6,117],[6,117],[6,118],[6,118],[6,118],[6,118],[6,118],[6,119],[6,119],[6,119],[6,119],[6,119],[6,120],[6,120],[6,120],[6,120],[6,120],[6,121],[6,121],[6,121],[6,121],[6,121],[6,122],[6,122],[6,122],[6,122],[6,122],[6,123],[6,123],[6,123],[6,123],[6,123],[6,124],[6,124],[6,124],[6,124],[6,124],[6,125],[6,125],[6,125],[6,125],[6,125],[6,126],[6,126],[6,126],[6,126],[6,126],[6,127],[6,127],[6,127],[6,127],[6,127],[6,128],[6,128],[6,128],[6,128],[6,128],[6,129],[6,129],[6,129],[6,129],[6,129],[6,130],[6,130],[6,130],[6,130],[6,130],[6,131],[6,131],[6,131],[6,131],[6,131],[6,132],[6,132],[6,132],[6,132],[6,132],[6,133],[6,133],[6,133],[6,133],[6,133],[6,134],[6,134],[6,134],[6,134],[6,134],[6,135],[6,135],[6,135],[6,135],[6,135],[6,136],[6,136],[6,136],[6,136],[6,136],[6,137],[6,137],[6,137],[6,137],[6,137],[6,138],[6,138],[6,138],[6,138],[6,138],[6,139],[6,139],[6,139],[6,139],[6,139],[6,140],[6,140],[6,140],[6,140],[6,140],[6,141],[6,141],[6,141],[6,141],[6,141],[6,142],[6,142],[6,142],[6,142],[6,142],[6,143],[6,143],[6,143],[6,143],[6,143],[6,144],[6,144],[6,144],[6,144],[6,144],[6,145],[6,145],[6,145],[6,145],[6,145],[6,146],[6,146],[6,146],[6,146],[6,146],[6,147],[6,147],[6,147],[6,147],[6,147],[6,148],[6,148],[6,148],[6,148],[6,148],[6,149],[6,149],[6,149],[6,149],[6,149],[6,150],[6,150],[6,150],[6,150],[6,150],[6,151],[6,151],[6,151],[6,151],[6,151],[6,152],[6,152],[6,152],[6,152],[6,152],[6,153],[6,153],[6,153],[6,153],[6,153],[6,154],[6,154],[6,154],[6,154],[6,154],[6,155],[6,155],[6,155],[6,155],[6,155],[6,156],[6,156],[6,156],[6,156],[6,156],[6,157],[6,157],[6,157],[6,157],[6,157],[6,158],[6,158],[6,158],[6,158],[6,158],[6,159],[6,159],[6,159],[6,159],[6,159],[6,160],[6,160],[6,160],[6,160],[6,160],[6,161],[6,161],[6,161],[6,161],[6,161],[6,162],[6,162],[6,162],[6,162],[6,162],[6,163],[6,163],[6,163],[6,163],[6,163],[6,164],[6,164],[6,164],[6,164],[6,164],[6,165],[6,165],[6,165],[6,165],[6,165],[6,166],[6,166],[6,166],[6,166],[6,166],[6,167],[6,167],[6,167],[6,167],[6,167],[6,168],[6,168],[6,168],[6,168],[6,168],[6,169],[6,169],[6,169],[6,169],[6,169],[6,170],[6,170],[6,170],[6,170],[6,170],[6,171],[6,171],[6,171],[6,171],[6,171],[6,172],[6,172],[6,172],[6,172],[6,172],[6,173],[6,173],[6,173],[6,173],[6,173],[6,174],[6,174],[6,174],[6,174],[6,174],[6,175],[6,175],[6,175],[6,175],[6,175],[6,176],[6,176],[6,176],[6,176],[6,176],[6,177],[6,177],[6,177],[6,177],[6,177],[6,178],[6,178],[6,178],[6,178],[6,178],[6,179],[6,179],[6,179],[6,179],[6,179],[6,180],[6,180],[6,180],[6,180],[6,180],[6,181],[6,181],[6,181],[6,181],[6,181],[6,182],[6,182],[6,182],[6,182],[6,182],[6,183],[6,183],[6,183],[6,183],[6,183],[6,184],[6,184],[6,184],[6,184],[6,184],[6,185],[6,185],[6,185],[6,185],[6,185],[6,186],[6,186],[6,186],[6,186],[6,186],[6,187],[6,187],[6,187],[6,187],[6,187],[6,188],[6,188],[6,188],[6,188],[6,188],[6,189],[6,189],[6,189],[6,189],[6,189],[6,190],[6,190],[6,190],[6,190],[6,190],[6,191],[6,191],[6,191],[6,191],[6,191],[6,192],[6,192],[6,192],[6,192],[6,192],[6,193],[6,193],[6,193],[6,193],[6,193],[6,194],[6,194],[6,194],[6,194],[6,194],[6,195],[6,195],[6,195],[6,195],[6,195],[6,196],[6,196],[6,196],[6,196],[6,196],[6,197],[6,197],[6,197],[6,197],[6,197],[6,198],[6,198],[6,198],[6,198],[6,198],[6,199],[6,199],[6,199],[6,199],[6,199],[6,200],[6,200],[6,200],[6,200],[6,200],[6,201],[6,201],[6,201],[6,201],[6,201],[6,202],[6,202],[6,202],[6,202],[6,202],[6,203],[6,203],[6,203],[6,203],[6,203],[6,204],[6,204],[6,204],[6,204],[6,204],[6,205],[6,205],[6,205],[6,205],[6,205],[6,206],[6,206],[6,206],[6,206],[6,206],[6,207],[6,207],[6,207],[6,207],[6,207],[6,208],[6,208],[6,208],[6,208],[6,208],[6,209],[6,209],[6,209],[6,209],[6,209],[6,210],[6,210],[6,210],[6,210],[6,210],[6,211],[6,211],[6,211],[6,211],[6,211],[6,212],[6,212],[6,212],[6,212],[6,212],[6,213],[6,213],[6,213],[6,213],[6,213],[6,214],[6,214],[6,214],[6,214],[6,214],[6,215],[6,215],[6,215],[6,215],[6,215],[6,216],[6,216],[6,216],[6,216],[6,216],[6,217],[6,217],[6,217],[6,217],[6,217],[6,218],[6,218],[6,218],[6,218],[6,218],[6,219],[6,219],[6,219],[6,219],[6,219],[6,220],[6,220],[6,220],[6,220],[6,220],[6,221],[6,221],[6,221],[6,221],[6,221],[6,222],[6,222],[6,222],[6,222],[6,222],[6,223],[6,223],[6,223],[6,223],[6,223],[6,224],[6,224],[6,224],[6,224],[6,224],[6,225],[6,225],[6,225],[6,225],[6,225],[6,226],[6,226],[6,226],[6,226],[6,226],[6,227],[6,227],[6,227],[6,227],[6,227],[6,228],[6,228],[6,228],[6,228],[6,228],[6,229],[6,229],[6,229],[6,229],[6,229],[6,230],[6,230],[6,230],[6,230],[6,230],[6,231],[6,231],[6,231],[6,231],[6,231],[6,232],[6,232],[6,232],[6,232],[6,232],[6,233],[6,233],[6,233],[6,233],[6,233],[6,234],[6,234],[6,234],[6,234],[6,234],[6,235],[6,235],[6,235],[6,235],[6,235],[6,236],[6,236],[6,236],[6,236],[6,236],[6,237],[6,237],[6,237],[6,237],[6,237],[6,238],[6,238],[6,238],[6,238],[6,238],[6,239],[6,239],[6,239],[6,239],[6,239],[6,240],[6,240],[6,240],[6,240],[6,240],[6,241],[6,241],[6,241],[6,241],[6,241],[6,242],[6,242],[6,242],[6,242],[6,242],[6,243],[6,243],[6,243],[6,243],[6,243],[6,244],[6,244],[6,244],[6,244],[6,244],[6,245],[6,245],[6,245],[6,245],[6,245],[6,246],[6,246],[6,246],[6,246],[6,246],[6,247],[6,247],[6,247],[6,247],[6,247],[6,248],[6,248],[6,248],[6,248],[6,248],[6,249],[6,249],[6,249],[6,249],[6,249],[6,250],[6,250],[6,250],[6,250],[6,250],[6,251],[6,251],[6,251],[6,251],[6,251],[6,252],[6,252],[6,252],[6,252],[6,252],[6,253],[6,253],[6,253],[6,253],[6,253],[6,254],[6,254],[6,254],[6,254],[6,254],[6,255],[6,255],[6,255],[6,255],[6,255],[6,256],[6,256],[6,256],[6,256],[6,256],[6,257],[6,257],[6,257],[6,257],[6,257],[6,258],[6,258],[6,258],[6,258],[6,258],[6,259],[6,259],[6,259],[6,259],[6,259],[6,260],[6,260],[6,260],[6,260],[6,260],[6,261],[6,261],[6,261],[6,261],[6,261],[6,262],[6,262],[6,262],[6,262],[6,262],[6,263],[6,263],[6,263],[6,263],[6,263],[6,264],[6,264],[6,264],[6,264],[6,264],[6,265],[6,265],[6,265],[6,265],[6,265],[6,266],[6,266],[6,266],[6,266],[6,266],[6,267],[6,267],[6,267],[6,267],[6,267],[6,268],[6,268],[6,268],[6,268],[6,268],[6,269],[6,269],[6,269],[6,269],[6,269],[6,270],[6,270],[6,270],[6,270],[6,270],[6,271],[6,271],[6,271],[6,271],[6,271],[6,272],[6,272],[6,272],[6,272],[6,272],[6,273],[6,273],[6,273],[6,273],[6,273],[6,274],[6,274],[6,274],[6,274],[6,274],[6,275],[6,275],[6,275],[6,275],[6,275],[6,276],[6,276],[6,276],[6,276],[6,276],[6,277],[6,277],[6,277],[6,277],[6,277],[6,278],[6,278],[6,278],[6,278],[6,278],[6,279],[6,279],[6,279],[6,279],[6,279],[6,280],[6,280],[6,280],[6,280],[6,280],[6,281],[6,281],[6,281],[6,281],[6,281],[6,282],[6,282],[6,282],[6,282],[6,282],[6,283],[6,283],[6,283],[6,283],[6,283],[6,284],[6,284],[6,284],[6,284],[6,284],[6,285],[6,285],[6,285],[6,285],[6,285],[6,286],[6,286],[6,286],[6,286],[6,286],[6,287],[6,287],[6,287],[6,287],[6,287],[6,288],[6,288],[6,288],[6,288],[6,288],[6,289],[6,289],[6,289],[6,289],[6,289],[6,290],[6,290],[6,290],[6,290],[6,290],[6,291],[6,291],[6,291],[6,291],[6,291],[6,292],[6,292],[6,292],[6,292],[6,292],[6,293],[6,293],[6,293],[6,293],[6,293],[6,294],[6,294],[6,294],[6,294],[6,294],[6,295],[6,295],[6,295],[6,295],[6,295],[6,296],[6,296],[6,296],[6,296],[6,296],[6,297],[6,297],[6,297],[6,297],[6,297],[6,298],[6,298],[6,298],[6,298],[6,298],[6,299],[6,299],[6,299],[6,299],[6,299],[6,300],[6,300],[6,300],[6,300],[6,300],[6,301],[6,301],[6,301],[6,301],[6,301],[6,302],[6,302],[6,302],[6,302],[6,302],[6,303],[6,303],[6,303],[6,303],[6,303],[6,304],[6,304],[6,304],[6,304],[6,304],[6,305],[6,305],[6,305],[6,305],[6,305],[6,306],[6,306],[6,306],[6,306],[6,306],[6,307],[6,307],[6,307],[6,307],[6,307],[6,308],[6,308],[6,308],[6,308],[6,308],[6,309],[6,309],[6,309],[6,309],[6,309],[6,310],[6,310],[6,310],[6,310],[6,310],[6,311],[6,311],[6,311],[6,311],[6,311],[6,312],[6,312],[6,312],[6,312],[6,312],[6,313],[6,313],[6,313],[6,313],[6,313],[6,314],[6,314],[6,314],[6,314],[6,314],[6,315],[6,315],[6,315],[6,315],[6,315],[6,316],[6,316],[6,316],[6,316],[6,316],[6,317],[6,317],[6,317],[6,317],[6,317],[6,318],[6,318],[6,318],[6,318],[6,318],[6,319],[6,319],[6,319],[6,319],[6,319],[6,320],[6,320],[6,320],[6,320],[6,320],[6,321],[6,321],[6,321],[6,321],[6,321],[6,322],[6,322],[6,322],[6,322],[6,322],[6,323],[6,323],[6,323],[6,323],[6,323],[6,324],[6,324],[6,324],[6,324],[6,324],[6,325],[6,325],[6,325],[6,325],[6,325],[6,326],[6,326],[6,326],[6,326],[6,326],[6,327],[6,327],[6,327],[6,327],[6,327],[6,328],[6,328],[6,328],[6,328],[6,328],[6,329],[6,329],[6,329],[6,329],[6,329],[6,330],[6,330],[6,330],[6,330],[6,330],[6,331],[6,331],[6,331],[6,331],[6,331],[6,332],[6,332],[6,332],[6,332],[6,332],[6,333],[6,333],[6,333],[6,333],[6,333],[6,334],[6,334],[6,334],[6,334],[6,334],[6,335],[6,335],[6,335],[6,335],[6,335],[6,336],[6,336],[6,336],[6,336],[6,336],[6,337],[6,337],[6,337],[6,337],[6,337],[6,338],[6,338],[6,338],[6,338],[6,338],[6,339],[6,339],[6,339],[6,339],[6,339],[6,340],[6,340],[6,340],[6,340],[6,340],[6,341],[6,341],[6,341],[6,341],[6,341],[6,342],[6,342],[6,342],[6,342],[6,342],[6,343],[6,343],[6,343],[6,343],[6,343],[6,344],[6,344],[6,344],[6,344],[6,344],[6,345],[6,345],[6,345],[6,345],[6,345],[6,346],[6,346],[6,346],[6,346],[6,346],[6,347],[6,347],[6,347],[6,347],[6,347],[6,348],[6,348],[6,348],[6,348],[6,348],[6,349],[6,349],[6,349],[6,349],[6,349],[6,350],[6,350],[6,350],[6,350],[6,350],[6,351],[6,351],[6,351],[6,351],[6,351],[6,352],[6,352],[6,352],[6,352],[6,352],[6,353],[6,353],[6,353],[6,353],[6,353],[6,354],[6,354],[6,354],[6,354],[6,354],[6,355],[6,355],[6,355],[6,355],[6,355],[6,356],[6,356],[6,356],[6,356],[6,356],[6,357],[6,357],[6,357],[6,357],[6,357],[6,358],[6,358],[6,358],[6,358],[6,358],[6,359],[6,359],[6,359],[6,359],[6,359],[6,360],[6,360],[6,360],[6,360],[6,360],[6,361],[6,361],[6,361],[6,361],[6,361],[6,362],[6,362],[6,362],[6,362],[6,362],[6,363],[6,363],[6,363],[6,363],[6,363],[6,364],[6,364],[6,364],[6,364],[6,364],[6,365],[6,365],[6,365],[6,365],[6,365],[6,366],[6,366],[6,366],[6,366],[6,366],[6,367],[6,367],[6,367],[6,367],[6,367],[6,368],[6,368],[6,368],[6,368],[6,368],[6,369],[6,369],[6,369],[6,369],[6,369],[6,370],[6,370],[6,370],[6,370],[6,370],[6,371],[6,371],[6,371],[6,371],[6,371],[6,372],[6,372],[6,372],[6,372],[6,372],[6,373],[6,373],[6,373],[6,373],[6,373],[6,374],[6,374],[6,374],[6,374],[6,374],[6,375],[6,375],[6,375],[6,375],[6,375],[6,376],[6,376],[6,376],[6,376],[6,376],[6,377],[6,377],[6,377],[6,377],[6,377],[6,378],[6,378],[6,378],[6,378],[6,378],[6,379],[6,379],[6,379],[6,379],[6,379],[6,380],[6,380],[6,380],[6,380],[6,380],[6,381],[6,381],[6,381],[6,381],[6,381],[6,382],[6,382],[6,382],[6,382],[6,382],[6,383],[6,383],[6,383],[6,383],[6,383],[6,384],[6,384],[6,384],[6,384],[6,384],[6,385],[6,385],[6,385],[6,385],[6,385],[6,386],[6,386],[6,386],[6,386],[6,386],[6,387],[6,387],[6,387],[6,387],[6,387],[6,388],[6,388],[6,388],[6,388],[6,388],[6,389],[6,389],[6,389],[6,389],[6,389],[6,390],[6,390],[6,390],[6,390],[6,390],[6,391],[6,391],[6,391],[6,391],[6,391],[6,392],[6,392],[6,392],[6,392],[6,392],[6,393],[6,393],[6,393],[6,393],[6,393],[6,394],[6,394],[6,394],[6,394],[6,394],[6,395],[6,395],[6,395],[6,395],[6,395],[6,396],[6,396],[6,396],[6,396],[6,396],[6,397],[6,397],[6,397],[6,397],[6,397],[6,398],[6,398],[6,398],[6,398],[6,398],[6,399],[6,399],[6,399],[6,399],[6,399],[6,400],[6,400],[6,400],[6,400],[6,400],[6,401],[6,401],[6,401],[6,401],[6,401],[6,402],[6,402],[6,402],[6,402],[6,402],[6,403],[6,403],[6,403],[6,403],[6,403],[6,404],[6,404],[6,404],[6,404],[6,404],[6,405],[6,405],[6,405],[6,405],[6,405],[6,406],[6,406],[6,406],[6,406],[6,406],[6,407],[6,407],[6,407],[6,407],[6,407],[6,408],[6,408],[6,408],[6,408],[6,408],[6,409],[6,409],[6,409],[6,409],[6,409],[6,410],[6,410],[6,410],[6,410],[6,410],[6,411],[6,411],[6,411],[6,411],[6,411],[6,412],[6,412],[6,412],[6,412],[6,412],[6,413],[6,413],[6,413],[6,413],[6,413],[6,414],[6,414],[6,414],[6,414],[6,414],[6,415],[6,415],[6,415],[6,415],[6,415],[6,416],[6,416],[6,416],[6,416],[6,416],[6,417],[6,417],[6,417],[6,417],[6,417],[6,418],[6,418],[6,418],[6,418],[6,418],[6,419],[6,419],[6,419],[6,419],[6,419],[6,420],[6,420],[6,420],[6,420],[6,420],[6,421],[6,421],[6,421],[6,421],[6,421],[6,422],[6,422],[6,422],[6,422],[6,422],[6,423],[6,423],[6,423],[6,423],[6,423],[6,424],[6,424],[6,424],[6,424],[6,424],[6,425],[6,425],[6,425],[6,425],[6,425],[6,426],[6,426],[6,426],[6,426],[6,426],[6,427],[6,427],[6,427],[6,427],[6,427],[6,428],[6,428],[6,428],[6,428],[6,428],[6,429],[6,429],[6,429],[6,429],[6,429],[6,430],[6,430],[6,430],[6,430],[6,430],[6,431],[6,431],[6,431],[6,431],[6,431],[6,432],[6,432],[6,432],[6,432],[6,432],[6,433],[6,433],[6,433],[6,433],[6,433],[6,434],[6,434],[6,434],[6,434],[6,434],[6,435],[6,435],[6,435],[6,435],[6,435],[6,436],[6,436],[6,436],[6,436],[6,436],[6,437],[6,437],[6,437],[6,437],[6,437],[6,438],[6,438],[6,438],[6,438],[6,438],[6,439],[6,439],[6,439],[6,439],[6,439],[6,440],[6,440],[6,440],[6,440],[6,440],[6,441],[6,441],[6,441],[6,441],[6,441],[6,442],[6,442],[6,442],[6,442],[6,442],[6,443],[6,443],[6,443],[6,443],[6,443],[6,444],[6,444],[6,444],[6,444],[6,444],[6,445],[6,445],[6,445],[6,445],[6,445],[6,446],[6,446],[6,446],[6,446],[6,446],[6,447],[6,447],[6,447],[6,447],[6,447],[6,448],[6,448],[6,448],[6,448],[6,448],[6,449],[6,449],[6,449],[6,449],[6,449],[6,450],[6,450],[6,450],[6,450],[6,450],[6,451],[6,451],[6,451],[6,451],[6,451],[6,452],[6,452],[6,452],[6,452],[6,452],[6,453],[6,453],[6,453],[6,453],[6,453],[6,454],[6,454],[6,454],[6,454],[6,454],[6,455],[6,455],[6,455],[6,455],[6,455],[6,456],[6,456],[6,456],[6,456],[6,456],[6,457],[6,457],[6,457],[6,457],[6,457],[6,458],[6,458],[6,458],[6,458],[6,458],[6,459],[6,459],[6,459],[6,459],[6,459],[6,460],[6,460],[6,460],[6,460],[6,460],[6,461],[6,461],[6,461],[6,461],[6,461],[6,462],[6,462],[6,462],[6,462],[6,462],[6,463],[6,463],[6,463],[6,463],[6,463],[6,464],[6,464],[6,464],[6,464],[6,464],[6,465],[6,465],[6,465],[6,465],[6,465],[6,466],[6,466],[6,466],[6,466],[6,466],[6,467],[6,467],[6,467],[6,467],[6,467],[6,468],[6,468],[6,468],[6,468],[6,468],[6,469],[6,469],[6,469],[6,469],[6,469],[6,470],[6,470],[6,470],[6,470],[6,470],[6,471],[6,471],[6,471],[6,471],[6,471],[6,472],[6,472],[6,472],[6,472],[6,472],[6,473],[6,473],[6,473],[6,473],[6,473],[6,474],[6,474],[6,474],[6,474],[6,474],[6,475],[6,475],[6,475],[6,475],[6,475],[6,476],[6,476],[6,476],[6,476],[6,476],[6,477],[6,477],[6,477],[6,477],[6,477],[6,478],[6,478],[6,478],[6,478],[6,478],[6,479],[6,479],[6,479],[6,479],[6,479],[6,480],[6,480],[6,480],[6,480],[6,480],[6,481],[6,481],[6,481],[6,481],[6,481],[6,482],[6,482],[6,482],[6,482],[6,482],[6,483],[6,483],[6,483],[6,483],[6,483],[6,484],[6,484],[6,484],[6,484],[6,484],[6,485],[6,485],[6,485],[6,485],[6,485],[6,486],[6,486],[6,486],[6,486],[6,486],[6,487],[6,487],[6,487],[6,487],[6,487],[6,488],[6,488],[6,488],[6,488],[6,488],[6,489],[6,489],[6,489],[6,489],[6,489],[6,490],[6,490],[6,490],[6,490],[6,490],[6,491],[6,491],[6,491],[6,491],[6,491],[6,492],[6,492],[6,492],[6,492],[6,492],[6,493],[6,493],[6,493],[6,493],[6,493],[6,494],[6,494],[6,494],[6,494],[6,494],[6,495],[6,495],[6,495],[6,495],[6,495],[6,496],[6,496],[6,496],[6,496],[6,496],[6,497],[6,497],[6,497],[6,497],[6,497],[6,498],[6,498],[6,498],[6,498],[6,498],[6,499],[6,499],[6,499],[6,499],[6,499],[6,500],[6,500],[6,500],[6,500],[6,500],[7,2],[7,2],[7,2],[7,2],[7,2],[7,3],[7,3],[7,3],[7,3],[7,3],[7,4],[7,4],[7,4],[7,4],[7,4],[7,5],[7,5],[7,5],[7,5],[7,5],[7,6],[7,6],[7,6],[7,6],[7,6],[7,7],[7,7],[7,7],[7,7],[7,7],[7,8],[7,8],[7,8],[7,8],[7,8],[7,9],[7,9],[7,9],[7,9],[7,9],[7,10],[7,10],[7,10],[7,10],[7,10],[7,11],[7,11],[7,11],[7,11],[7,11],[7,12],[7,12],[7,12],[7,12],[7,12],[7,13],[7,13],[7,13],[7,13],[7,13],[7,14],[7,14],[7,14],[7,14],[7,14],[7,15],[7,15],[7,15],[7,15],[7,15],[7,16],[7,16],[7,16],[7,16],[7,16],[7,17],[7,17],[7,17],[7,17],[7,17],[7,18],[7,18],[7,18],[7,18],[7,18],[7,19],[7,19],[7,19],[7,19],[7,19],[7,20],[7,20],[7,20],[7,20],[7,20],[7,21],[7,21],[7,21],[7,21],[7,21],[7,22],[7,22],[7,22],[7,22],[7,22],[7,23],[7,23],[7,23],[7,23],[7,23],[7,24],[7,24],[7,24],[7,24],[7,24],[7,25],[7,25],[7,25],[7,25],[7,25],[7,26],[7,26],[7,26],[7,26],[7,26],[7,27],[7,27],[7,27],[7,27],[7,27],[7,28],[7,28],[7,28],[7,28],[7,28],[7,29],[7,29],[7,29],[7,29],[7,29],[7,30],[7,30],[7,30],[7,30],[7,30],[7,31],[7,31],[7,31],[7,31],[7,31],[7,32],[7,32],[7,32],[7,32],[7,32],[7,33],[7,33],[7,33],[7,33],[7,33],[7,34],[7,34],[7,34],[7,34],[7,34],[7,35],[7,35],[7,35],[7,35],[7,35],[7,36],[7,36],[7,36],[7,36],[7,36],[7,37],[7,37],[7,37],[7,37],[7,37],[7,38],[7,38],[7,38],[7,38],[7,38],[7,39],[7,39],[7,39],[7,39],[7,39],[7,40],[7,40],[7,40],[7,40],[7,40],[7,41],[7,41],[7,41],[7,41],[7,41],[7,42],[7,42],[7,42],[7,42],[7,42],[7,43],[7,43],[7,43],[7,43],[7,43],[7,44],[7,44],[7,44],[7,44],[7,44],[7,45],[7,45],[7,45],[7,45],[7,45],[7,46],[7,46],[7,46],[7,46],[7,46],[7,47],[7,47],[7,47],[7,47],[7,47],[7,48],[7,48],[7,48],[7,48],[7,48],[7,49],[7,49],[7,49],[7,49],[7,49],[7,50],[7,50],[7,50],[7,50],[7,50],[7,51],[7,51],[7,51],[7,51],[7,51],[7,52],[7,52],[7,52],[7,52],[7,52],[7,53],[7,53],[7,53],[7,53],[7,53],[7,54],[7,54],[7,54],[7,54],[7,54],[7,55],[7,55],[7,55],[7,55],[7,55],[7,56],[7,56],[7,56],[7,56],[7,56],[7,57],[7,57],[7,57],[7,57],[7,57],[7,58],[7,58],[7,58],[7,58],[7,58],[7,59],[7,59],[7,59],[7,59],[7,59],[7,60],[7,60],[7,60],[7,60],[7,60],[7,61],[7,61],[7,61],[7,61],[7,61],[7,62],[7,62],[7,62],[7,62],[7,62],[7,63],[7,63],[7,63],[7,63],[7,63],[7,64],[7,64],[7,64],[7,64],[7,64],[7,65],[7,65],[7,65],[7,65],[7,65],[7,66],[7,66],[7,66],[7,66],[7,66],[7,67],[7,67],[7,67],[7,67],[7,67],[7,68],[7,68],[7,68],[7,68],[7,68],[7,69],[7,69],[7,69],[7,69],[7,69],[7,70],[7,70],[7,70],[7,70],[7,70],[7,71],[7,71],[7,71],[7,71],[7,71],[7,72],[7,72],[7,72],[7,72],[7,72],[7,73],[7,73],[7,73],[7,73],[7,73],[7,74],[7,74],[7,74],[7,74],[7,74],[7,75],[7,75],[7,75],[7,75],[7,75],[7,76],[7,76],[7,76],[7,76],[7,76],[7,77],[7,77],[7,77],[7,77],[7,77],[7,78],[7,78],[7,78],[7,78],[7,78],[7,79],[7,79],[7,79],[7,79],[7,79],[7,80],[7,80],[7,80],[7,80],[7,80],[7,81],[7,81],[7,81],[7,81],[7,81],[7,82],[7,82],[7,82],[7,82],[7,82],[7,83],[7,83],[7,83],[7,83],[7,83],[7,84],[7,84],[7,84],[7,84],[7,84],[7,85],[7,85],[7,85],[7,85],[7,85],[7,86],[7,86],[7,86],[7,86],[7,86],[7,87],[7,87],[7,87],[7,87],[7,87],[7,88],[7,88],[7,88],[7,88],[7,88],[7,89],[7,89],[7,89],[7,89],[7,89],[7,90],[7,90],[7,90],[7,90],[7,90],[7,91],[7,91],[7,91],[7,91],[7,91],[7,92],[7,92],[7,92],[7,92],[7,92],[7,93],[7,93],[7,93],[7,93],[7,93],[7,94],[7,94],[7,94],[7,94],[7,94],[7,95],[7,95],[7,95],[7,95],[7,95],[7,96],[7,96],[7,96],[7,96],[7,96],[7,97],[7,97],[7,97],[7,97],[7,97],[7,98],[7,98],[7,98],[7,98],[7,98],[7,99],[7,99],[7,99],[7,99],[7,99],[7,100],[7,100],[7,100],[7,100],[7,100],[7,101],[7,101],[7,101],[7,101],[7,101],[7,102],[7,102],[7,102],[7,102],[7,102],[7,103],[7,103],[7,103],[7,103],[7,103],[7,104],[7,104],[7,104],[7,104],[7,104],[7,105],[7,105],[7,105],[7,105],[7,105],[7,106],[7,106],[7,106],[7,106],[7,106],[7,107],[7,107],[7,107],[7,107],[7,107],[7,108],[7,108],[7,108],[7,108],[7,108],[7,109],[7,109],[7,109],[7,109],[7,109],[7,110],[7,110],[7,110],[7,110],[7,110],[7,111],[7,111],[7,111],[7,111],[7,111],[7,112],[7,112],[7,112],[7,112],[7,112],[7,113],[7,113],[7,113],[7,113],[7,113],[7,114],[7,114],[7,114],[7,114],[7,114],[7,115],[7,115],[7,115],[7,115],[7,115],[7,116],[7,116],[7,116],[7,116],[7,116],[7,117],[7,117],[7,117],[7,117],[7,117],[7,118],[7,118],[7,118],[7,118],[7,118],[7,119],[7,119],[7,119],[7,119],[7,119],[7,120],[7,120],[7,120],[7,120],[7,120],[7,121],[7,121],[7,121],[7,121],[7,121],[7,122],[7,122],[7,122],[7,122],[7,122],[7,123],[7,123],[7,123],[7,123],[7,123],[7,124],[7,124],[7,124],[7,124],[7,124],[7,125],[7,125],[7,125],[7,125],[7,125],[7,126],[7,126],[7,126],[7,126],[7,126],[7,127],[7,127],[7,127],[7,127],[7,127],[7,128],[7,128],[7,128],[7,128],[7,128],[7,129],[7,129],[7,129],[7,129],[7,129],[7,130],[7,130],[7,130],[7,130],[7,130],[7,131],[7,131],[7,131],[7,131],[7,131],[7,132],[7,132],[7,132],[7,132],[7,132],[7,133],[7,133],[7,133],[7,133],[7,133],[7,134],[7,134],[7,134],[7,134],[7,134],[7,135],[7,135],[7,135],[7,135],[7,135],[7,136],[7,136],[7,136],[7,136],[7,136],[7,137],[7,137],[7,137],[7,137],[7,137],[7,138],[7,138],[7,138],[7,138],[7,138],[7,139],[7,139],[7,139],[7,139],[7,139],[7,140],[7,140],[7,140],[7,140],[7,140],[7,141],[7,141],[7,141],[7,141],[7,141],[7,142],[7,142],[7,142],[7,142],[7,142],[7,143],[7,143],[7,143],[7,143],[7,143],[7,144],[7,144],[7,144],[7,144],[7,144],[7,145],[7,145],[7,145],[7,145],[7,145],[7,146],[7,146],[7,146],[7,146],[7,146],[7,147],[7,147],[7,147],[7,147],[7,147],[7,148],[7,148],[7,148],[7,148],[7,148],[7,149],[7,149],[7,149],[7,149],[7,149],[7,150],[7,150],[7,150],[7,150],[7,150],[7,151],[7,151],[7,151],[7,151],[7,151],[7,152],[7,152],[7,152],[7,152],[7,152],[7,153],[7,153],[7,153],[7,153],[7,153],[7,154],[7,154],[7,154],[7,154],[7,154],[7,155],[7,155],[7,155],[7,155],[7,155],[7,156],[7,156],[7,156],[7,156],[7,156],[7,157],[7,157],[7,157],[7,157],[7,157],[7,158],[7,158],[7,158],[7,158],[7,158],[7,159],[7,159],[7,159],[7,159],[7,159],[7,160],[7,160],[7,160],[7,160],[7,160],[7,161],[7,161],[7,161],[7,161],[7,161],[7,162],[7,162],[7,162],[7,162],[7,162],[7,163],[7,163],[7,163],[7,163],[7,163],[7,164],[7,164],[7,164],[7,164],[7,164],[7,165],[7,165],[7,165],[7,165],[7,165],[7,166],[7,166],[7,166],[7,166],[7,166],[7,167],[7,167],[7,167],[7,167],[7,167],[7,168],[7,168],[7,168],[7,168],[7,168],[7,169],[7,169],[7,169],[7,169],[7,169],[7,170],[7,170],[7,170],[7,170],[7,170],[7,171],[7,171],[7,171],[7,171],[7,171],[7,172],[7,172],[7,172],[7,172],[7,172],[7,173],[7,173],[7,173],[7,173],[7,173],[7,174],[7,174],[7,174],[7,174],[7,174],[7,175],[7,175],[7,175],[7,175],[7,175],[7,176],[7,176],[7,176],[7,176],[7,176],[7,177],[7,177],[7,177],[7,177],[7,177],[7,178],[7,178],[7,178],[7,178],[7,178],[7,179],[7,179],[7,179],[7,179],[7,179],[7,180],[7,180],[7,180],[7,180],[7,180],[7,181],[7,181],[7,181],[7,181],[7,181],[7,182],[7,182],[7,182],[7,182],[7,182],[7,183],[7,183],[7,183],[7,183],[7,183],[7,184],[7,184],[7,184],[7,184],[7,184],[7,185],[7,185],[7,185],[7,185],[7,185],[7,186],[7,186],[7,186],[7,186],[7,186],[7,187],[7,187],[7,187],[7,187],[7,187],[7,188],[7,188],[7,188],[7,188],[7,188],[7,189],[7,189],[7,189],[7,189],[7,189],[7,190],[7,190],[7,190],[7,190],[7,190],[7,191],[7,191],[7,191],[7,191],[7,191],[7,192],[7,192],[7,192],[7,192],[7,192],[7,193],[7,193],[7,193],[7,193],[7,193],[7,194],[7,194],[7,194],[7,194],[7,194],[7,195],[7,195],[7,195],[7,195],[7,195],[7,196],[7,196],[7,196],[7,196],[7,196],[7,197],[7,197],[7,197],[7,197],[7,197],[7,198],[7,198],[7,198],[7,198],[7,198],[7,199],[7,199],[7,199],[7,199],[7,199],[7,200],[7,200],[7,200],[7,200],[7,200],[7,201],[7,201],[7,201],[7,201],[7,201],[7,202],[7,202],[7,202],[7,202],[7,202],[7,203],[7,203],[7,203],[7,203],[7,203],[7,204],[7,204],[7,204],[7,204],[7,204],[7,205],[7,205],[7,205],[7,205],[7,205],[7,206],[7,206],[7,206],[7,206],[7,206],[7,207],[7,207],[7,207],[7,207],[7,207],[7,208],[7,208],[7,208],[7,208],[7,208],[7,209],[7,209],[7,209],[7,209],[7,209],[7,210],[7,210],[7,210],[7,210],[7,210],[7,211],[7,211],[7,211],[7,211],[7,211],[7,212],[7,212],[7,212],[7,212],[7,212],[7,213],[7,213],[7,213],[7,213],[7,213],[7,214],[7,214],[7,214],[7,214],[7,214],[7,215],[7,215],[7,215],[7,215],[7,215],[7,216],[7,216],[7,216],[7,216],[7,216],[7,217],[7,217],[7,217],[7,217],[7,217],[7,218],[7,218],[7,218],[7,218],[7,218],[7,219],[7,219],[7,219],[7,219],[7,219],[7,220],[7,220],[7,220],[7,220],[7,220],[7,221],[7,221],[7,221],[7,221],[7,221],[7,222],[7,222],[7,222],[7,222],[7,222],[7,223],[7,223],[7,223],[7,223],[7,223],[7,224],[7,224],[7,224],[7,224],[7,224],[7,225],[7,225],[7,225],[7,225],[7,225],[7,226],[7,226],[7,226],[7,226],[7,226],[7,227],[7,227],[7,227],[7,227],[7,227],[7,228],[7,228],[7,228],[7,228],[7,228],[7,229],[7,229],[7,229],[7,229],[7,229],[7,230],[7,230],[7,230],[7,230],[7,230],[7,231],[7,231],[7,231],[7,231],[7,231],[7,232],[7,232],[7,232],[7,232],[7,232],[7,233],[7,233],[7,233],[7,233],[7,233],[7,234],[7,234],[7,234],[7,234],[7,234],[7,235],[7,235],[7,235],[7,235],[7,235],[7,236],[7,236],[7,236],[7,236],[7,236],[7,237],[7,237],[7,237],[7,237],[7,237],[7,238],[7,238],[7,238],[7,238],[7,238],[7,239],[7,239],[7,239],[7,239],[7,239],[7,240],[7,240],[7,240],[7,240],[7,240],[7,241],[7,241],[7,241],[7,241],[7,241],[7,242],[7,242],[7,242],[7,242],[7,242],[7,243],[7,243],[7,243],[7,243],[7,243],[7,244],[7,244],[7,244],[7,244],[7,244],[7,245],[7,245],[7,245],[7,245],[7,245],[7,246],[7,246],[7,246],[7,246],[7,246],[7,247],[7,247],[7,247],[7,247],[7,247],[7,248],[7,248],[7,248],[7,248],[7,248],[7,249],[7,249],[7,249],[7,249],[7,249],[7,250],[7,250],[7,250],[7,250],[7,250],[7,251],[7,251],[7,251],[7,251],[7,251],[7,252],[7,252],[7,252],[7,252],[7,252],[7,253],[7,253],[7,253],[7,253],[7,253],[7,254],[7,254],[7,254],[7,254],[7,254],[7,255],[7,255],[7,255],[7,255],[7,255],[7,256],[7,256],[7,256],[7,256],[7,256],[7,257],[7,257],[7,257],[7,257],[7,257],[7,258],[7,258],[7,258],[7,258],[7,258],[7,259],[7,259],[7,259],[7,259],[7,259],[7,260],[7,260],[7,260],[7,260],[7,260],[7,261],[7,261],[7,261],[7,261],[7,261],[7,262],[7,262],[7,262],[7,262],[7,262],[7,263],[7,263],[7,263],[7,263],[7,263],[7,264],[7,264],[7,264],[7,264],[7,264],[7,265],[7,265],[7,265],[7,265],[7,265],[7,266],[7,266],[7,266],[7,266],[7,266],[7,267],[7,267],[7,267],[7,267],[7,267],[7,268],[7,268],[7,268],[7,268],[7,268],[7,269],[7,269],[7,269],[7,269],[7,269],[7,270],[7,270],[7,270],[7,270],[7,270],[7,271],[7,271],[7,271],[7,271],[7,271],[7,272],[7,272],[7,272],[7,272],[7,272],[7,273],[7,273],[7,273],[7,273],[7,273],[7,274],[7,274],[7,274],[7,274],[7,274],[7,275],[7,275],[7,275],[7,275],[7,275],[7,276],[7,276],[7,276],[7,276],[7,276],[7,277],[7,277],[7,277],[7,277],[7,277],[7,278],[7,278],[7,278],[7,278],[7,278],[7,279],[7,279],[7,279],[7,279],[7,279],[7,280],[7,280],[7,280],[7,280],[7,280],[7,281],[7,281],[7,281],[7,281],[7,281],[7,282],[7,282],[7,282],[7,282],[7,282],[7,283],[7,283],[7,283],[7,283],[7,283],[7,284],[7,284],[7,284],[7,284],[7,284],[7,285],[7,285],[7,285],[7,285],[7,285],[7,286],[7,286],[7,286],[7,286],[7,286],[7,287],[7,287],[7,287],[7,287],[7,287],[7,288],[7,288],[7,288],[7,288],[7,288],[7,289],[7,289],[7,289],[7,289],[7,289],[7,290],[7,290],[7,290],[7,290],[7,290],[7,291],[7,291],[7,291],[7,291],[7,291],[7,292],[7,292],[7,292],[7,292],[7,292],[7,293],[7,293],[7,293],[7,293],[7,293],[7,294],[7,294],[7,294],[7,294],[7,294],[7,295],[7,295],[7,295],[7,295],[7,295],[7,296],[7,296],[7,296],[7,296],[7,296],[7,297],[7,297],[7,297],[7,297],[7,297],[7,298],[7,298],[7,298],[7,298],[7,298],[7,299],[7,299],[7,299],[7,299],[7,299],[7,300],[7,300],[7,300],[7,300],[7,300],[7,301],[7,301],[7,301],[7,301],[7,301],[7,302],[7,302],[7,302],[7,302],[7,302],[7,303],[7,303],[7,303],[7,303],[7,303],[7,304],[7,304],[7,304],[7,304],[7,304],[7,305],[7,305],[7,305],[7,305],[7,305],[7,306],[7,306],[7,306],[7,306],[7,306],[7,307],[7,307],[7,307],[7,307],[7,307],[7,308],[7,308],[7,308],[7,308],[7,308],[7,309],[7,309],[7,309],[7,309],[7,309],[7,310],[7,310],[7,310],[7,310],[7,310],[7,311],[7,311],[7,311],[7,311],[7,311],[7,312],[7,312],[7,312],[7,312],[7,312],[7,313],[7,313],[7,313],[7,313],[7,313],[7,314],[7,314],[7,314],[7,314],[7,314],[7,315],[7,315],[7,315],[7,315],[7,315],[7,316],[7,316],[7,316],[7,316],[7,316],[7,317],[7,317],[7,317],[7,317],[7,317],[7,318],[7,318],[7,318],[7,318],[7,318],[7,319],[7,319],[7,319],[7,319],[7,319],[7,320],[7,320],[7,320],[7,320],[7,320],[7,321],[7,321],[7,321],[7,321],[7,321],[7,322],[7,322],[7,322],[7,322],[7,322],[7,323],[7,323],[7,323],[7,323],[7,323],[7,324],[7,324],[7,324],[7,324],[7,324],[7,325],[7,325],[7,325],[7,325],[7,325],[7,326],[7,326],[7,326],[7,326],[7,326],[7,327],[7,327],[7,327],[7,327],[7,327],[7,328],[7,328],[7,328],[7,328],[7,328],[7,329],[7,329],[7,329],[7,329],[7,329],[7,330],[7,330],[7,330],[7,330],[7,330],[7,331],[7,331],[7,331],[7,331],[7,331],[7,332],[7,332],[7,332],[7,332],[7,332],[7,333],[7,333],[7,333],[7,333],[7,333],[7,334],[7,334],[7,334],[7,334],[7,334],[7,335],[7,335],[7,335],[7,335],[7,335],[7,336],[7,336],[7,336],[7,336],[7,336],[7,337],[7,337],[7,337],[7,337],[7,337],[7,338],[7,338],[7,338],[7,338],[7,338],[7,339],[7,339],[7,339],[7,339],[7,339],[7,340],[7,340],[7,340],[7,340],[7,340],[7,341],[7,341],[7,341],[7,341],[7,341],[7,342],[7,342],[7,342],[7,342],[7,342],[7,343],[7,343],[7,343],[7,343],[7,343],[7,344],[7,344],[7,344],[7,344],[7,344],[7,345],[7,345],[7,345],[7,345],[7,345],[7,346],[7,346],[7,346],[7,346],[7,346],[7,347],[7,347],[7,347],[7,347],[7,347],[7,348],[7,348],[7,348],[7,348],[7,348],[7,349],[7,349],[7,349],[7,349],[7,349],[7,350],[7,350],[7,350],[7,350],[7,350],[7,351],[7,351],[7,351],[7,351],[7,351],[7,352],[7,352],[7,352],[7,352],[7,352],[7,353],[7,353],[7,353],[7,353],[7,353],[7,354],[7,354],[7,354],[7,354],[7,354],[7,355],[7,355],[7,355],[7,355],[7,355],[7,356],[7,356],[7,356],[7,356],[7,356],[7,357],[7,357],[7,357],[7,357],[7,357],[7,358],[7,358],[7,358],[7,358],[7,358],[7,359],[7,359],[7,359],[7,359],[7,359],[7,360],[7,360],[7,360],[7,360],[7,360],[7,361],[7,361],[7,361],[7,361],[7,361],[7,362],[7,362],[7,362],[7,362],[7,362],[7,363],[7,363],[7,363],[7,363],[7,363],[7,364],[7,364],[7,364],[7,364],[7,364],[7,365],[7,365],[7,365],[7,365],[7,365],[7,366],[7,366],[7,366],[7,366],[7,366],[7,367],[7,367],[7,367],[7,367],[7,367],[7,368],[7,368],[7,368],[7,368],[7,368],[7,369],[7,369],[7,369],[7,369],[7,369],[7,370],[7,370],[7,370],[7,370],[7,370],[7,371],[7,371],[7,371],[7,371],[7,371],[7,372],[7,372],[7,372],[7,372],[7,372],[7,373],[7,373],[7,373],[7,373],[7,373],[7,374],[7,374],[7,374],[7,374],[7,374],[7,375],[7,375],[7,375],[7,375],[7,375],[7,376],[7,376],[7,376],[7,376],[7,376],[7,377],[7,377],[7,377],[7,377],[7,377],[7,378],[7,378],[7,378],[7,378],[7,378],[7,379],[7,379],[7,379],[7,379],[7,379],[7,380],[7,380],[7,380],[7,380],[7,380],[7,381],[7,381],[7,381],[7,381],[7,381],[7,382],[7,382],[7,382],[7,382],[7,382],[7,383],[7,383],[7,383],[7,383],[7,383],[7,384],[7,384],[7,384],[7,384],[7,384],[7,385],[7,385],[7,385],[7,385],[7,385],[7,386],[7,386],[7,386],[7,386],[7,386],[7,387],[7,387],[7,387],[7,387],[7,387],[7,388],[7,388],[7,388],[7,388],[7,388],[7,389],[7,389],[7,389],[7,389],[7,389],[7,390],[7,390],[7,390],[7,390],[7,390],[7,391],[7,391],[7,391],[7,391],[7,391],[7,392],[7,392],[7,392],[7,392],[7,392],[7,393],[7,393],[7,393],[7,393],[7,393],[7,394],[7,394],[7,394],[7,394],[7,394],[7,395],[7,395],[7,395],[7,395],[7,395],[7,396],[7,396],[7,396],[7,396],[7,396],[7,397],[7,397],[7,397],[7,397],[7,397],[7,398],[7,398],[7,398],[7,398],[7,398],[7,399],[7,399],[7,399],[7,399],[7,399],[7,400],[7,400],[7,400],[7,400],[7,400],[7,401],[7,401],[7,401],[7,401],[7,401],[7,402],[7,402],[7,402],[7,402],[7,402],[7,403],[7,403],[7,403],[7,403],[7,403],[7,404],[7,404],[7,404],[7,404],[7,404],[7,405],[7,405],[7,405],[7,405],[7,405],[7,406],[7,406],[7,406],[7,406],[7,406],[7,407],[7,407],[7,407],[7,407],[7,407],[7,408],[7,408],[7,408],[7,408],[7,408],[7,409],[7,409],[7,409],[7,409],[7,409],[7,410],[7,410],[7,410],[7,410],[7,410],[7,411],[7,411],[7,411],[7,411],[7,411],[7,412],[7,412],[7,412],[7,412],[7,412],[7,413],[7,413],[7,413],[7,413],[7,413],[7,414],[7,414],[7,414],[7,414],[7,414],[7,415],[7,415],[7,415],[7,415],[7,415],[7,416],[7,416],[7,416],[7,416],[7,416],[7,417],[7,417],[7,417],[7,417],[7,417],[7,418],[7,418],[7,418],[7,418],[7,418],[7,419],[7,419],[7,419],[7,419],[7,419],[7,420],[7,420],[7,420],[7,420],[7,420],[7,421],[7,421],[7,421],[7,421],[7,421],[7,422],[7,422],[7,422],[7,422],[7,422],[7,423],[7,423],[7,423],[7,423],[7,423],[7,424],[7,424],[7,424],[7,424],[7,424],[7,425],[7,425],[7,425],[7,425],[7,425],[7,426],[7,426],[7,426],[7,426],[7,426],[7,427],[7,427],[7,427],[7,427],[7,427],[7,428],[7,428],[7,428],[7,428],[7,428],[7,429],[7,429],[7,429],[7,429],[7,429],[7,430],[7,430],[7,430],[7,430],[7,430],[7,431],[7,431],[7,431],[7,431],[7,431],[7,432],[7,432],[7,432],[7,432],[7,432],[7,433],[7,433],[7,433],[7,433],[7,433],[7,434],[7,434],[7,434],[7,434],[7,434],[7,435],[7,435],[7,435],[7,435],[7,435],[7,436],[7,436],[7,436],[7,436],[7,436],[7,437],[7,437],[7,437],[7,437],[7,437],[7,438],[7,438],[7,438],[7,438],[7,438],[7,439],[7,439],[7,439],[7,439],[7,439],[7,440],[7,440],[7,440],[7,440],[7,440],[7,441],[7,441],[7,441],[7,441],[7,441],[7,442],[7,442],[7,442],[7,442],[7,442],[7,443],[7,443],[7,443],[7,443],[7,443],[7,444],[7,444],[7,444],[7,444],[7,444],[7,445],[7,445],[7,445],[7,445],[7,445],[7,446],[7,446],[7,446],[7,446],[7,446],[7,447],[7,447],[7,447],[7,447],[7,447],[7,448],[7,448],[7,448],[7,448],[7,448],[7,449],[7,449],[7,449],[7,449],[7,449],[7,450],[7,450],[7,450],[7,450],[7,450],[7,451],[7,451],[7,451],[7,451],[7,451],[7,452],[7,452],[7,452],[7,452],[7,452],[7,453],[7,453],[7,453],[7,453],[7,453],[7,454],[7,454],[7,454],[7,454],[7,454],[7,455],[7,455],[7,455],[7,455],[7,455],[7,456],[7,456],[7,456],[7,456],[7,456],[7,457],[7,457],[7,457],[7,457],[7,457],[7,458],[7,458],[7,458],[7,458],[7,458],[7,459],[7,459],[7,459],[7,459],[7,459],[7,460],[7,460],[7,460],[7,460],[7,460],[7,461],[7,461],[7,461],[7,461],[7,461],[7,462],[7,462],[7,462],[7,462],[7,462],[7,463],[7,463],[7,463],[7,463],[7,463],[7,464],[7,464],[7,464],[7,464],[7,464],[7,465],[7,465],[7,465],[7,465],[7,465],[7,466],[7,466],[7,466],[7,466],[7,466],[7,467],[7,467],[7,467],[7,467],[7,467],[7,468],[7,468],[7,468],[7,468],[7,468],[7,469],[7,469],[7,469],[7,469],[7,469],[7,470],[7,470],[7,470],[7,470],[7,470],[7,471],[7,471],[7,471],[7,471],[7,471],[7,472],[7,472],[7,472],[7,472],[7,472],[7,473],[7,473],[7,473],[7,473],[7,473],[7,474],[7,474],[7,474],[7,474],[7,474],[7,475],[7,475],[7,475],[7,475],[7,475],[7,476],[7,476],[7,476],[7,476],[7,476],[7,477],[7,477],[7,477],[7,477],[7,477],[7,478],[7,478],[7,478],[7,478],[7,478],[7,479],[7,479],[7,479],[7,479],[7,479],[7,480],[7,480],[7,480],[7,480],[7,480],[7,481],[7,481],[7,481],[7,481],[7,481],[7,482],[7,482],[7,482],[7,482],[7,482],[7,483],[7,483],[7,483],[7,483],[7,483],[7,484],[7,484],[7,484],[7,484],[7,484],[7,485],[7,485],[7,485],[7,485],[7,485],[7,486],[7,486],[7,486],[7,486],[7,486],[7,487],[7,487],[7,487],[7,487],[7,487],[7,488],[7,488],[7,488],[7,488],[7,488],[7,489],[7,489],[7,489],[7,489],[7,489],[7,490],[7,490],[7,490],[7,490],[7,490],[7,491],[7,491],[7,491],[7,491],[7,491],[7,492],[7,492],[7,492],[7,492],[7,492],[7,493],[7,493],[7,493],[7,493],[7,493],[7,494],[7,494],[7,494],[7,494],[7,494],[7,495],[7,495],[7,495],[7,495],[7,495],[7,496],[7,496],[7,496],[7,496],[7,496],[7,497],[7,497],[7,497],[7,497],[7,497],[7,498],[7,498],[7,498],[7,498],[7,498],[7,499],[7,499],[7,499],[7,499],[7,499],[7,500],[7,500],[7,500],[7,500],[7,500],[8,2],[8,2],[8,2],[8,2],[8,3],[8,3],[8,3],[8,3],[8,4],[8,4],[8,4],[8,4],[8,5],[8,5],[8,5],[8,5],[8,6],[8,6],[8,6],[8,6],[8,7],[8,7],[8,7],[8,7],[8,8],[8,8],[8,8],[8,8],[8,9],[8,9],[8,9],[8,9],[8,10],[8,10],[8,10],[8,10],[8,11],[8,11],[8,11],[8,11],[8,12],[8,12],[8,12],[8,12],[8,13],[8,13],[8,13],[8,13],[8,14],[8,14],[8,14],[8,14],[8,15],[8,15],[8,15],[8,15],[8,16],[8,16],[8,16],[8,16],[8,17],[8,17],[8,17],[8,17],[8,18],[8,18],[8,18],[8,18],[8,19],[8,19],[8,19],[8,19],[8,20],[8,20],[8,20],[8,20],[8,21],[8,21],[8,21],[8,21],[8,22],[8,22],[8,22],[8,22],[8,23],[8,23],[8,23],[8,23],[8,24],[8,24],[8,24],[8,24],[8,25],[8,25],[8,25],[8,25],[8,26],[8,26],[8,26],[8,26],[8,27],[8,27],[8,27],[8,27],[8,28],[8,28],[8,28],[8,28],[8,29],[8,29],[8,29],[8,29],[8,30],[8,30],[8,30],[8,30],[8,31],[8,31],[8,31],[8,31],[8,32],[8,32],[8,32],[8,32],[8,33],[8,33],[8,33],[8,33],[8,34],[8,34],[8,34],[8,34],[8,35],[8,35],[8,35],[8,35],[8,36],[8,36],[8,36],[8,36],[8,37],[8,37],[8,37],[8,37],[8,38],[8,38],[8,38],[8,38],[8,39],[8,39],[8,39],[8,39],[8,40],[8,40],[8,40],[8,40],[8,41],[8,41],[8,41],[8,41],[8,42],[8,42],[8,42],[8,42],[8,43],[8,43],[8,43],[8,43],[8,44],[8,44],[8,44],[8,44],[8,45],[8,45],[8,45],[8,45],[8,46],[8,46],[8,46],[8,46],[8,47],[8,47],[8,47],[8,47],[8,48],[8,48],[8,48],[8,48],[8,49],[8,49],[8,49],[8,49],[8,50],[8,50],[8,50],[8,50],[8,51],[8,51],[8,51],[8,51],[8,52],[8,52],[8,52],[8,52],[8,53],[8,53],[8,53],[8,53],[8,54],[8,54],[8,54],[8,54],[8,55],[8,55],[8,55],[8,55],[8,56],[8,56],[8,56],[8,56],[8,57],[8,57],[8,57],[8,57],[8,58],[8,58],[8,58],[8,58],[8,59],[8,59],[8,59],[8,59],[8,60],[8,60],[8,60],[8,60],[8,61],[8,61],[8,61],[8,61],[8,62],[8,62],[8,62],[8,62],[8,63],[8,63],[8,63],[8,63],[8,64],[8,64],[8,64],[8,64],[8,65],[8,65],[8,65],[8,65],[8,66],[8,66],[8,66],[8,66],[8,67],[8,67],[8,67],[8,67],[8,68],[8,68],[8,68],[8,68],[8,69],[8,69],[8,69],[8,69],[8,70],[8,70],[8,70],[8,70],[8,71],[8,71],[8,71],[8,71],[8,72],[8,72],[8,72],[8,72],[8,73],[8,73],[8,73],[8,73],[8,74],[8,74],[8,74],[8,74],[8,75],[8,75],[8,75],[8,75],[8,76],[8,76],[8,76],[8,76],[8,77],[8,77],[8,77],[8,77],[8,78],[8,78],[8,78],[8,78],[8,79],[8,79],[8,79],[8,79],[8,80],[8,80],[8,80],[8,80],[8,81],[8,81],[8,81],[8,81],[8,82],[8,82],[8,82],[8,82],[8,83],[8,83],[8,83],[8,83],[8,84],[8,84],[8,84],[8,84],[8,85],[8,85],[8,85],[8,85],[8,86],[8,86],[8,86],[8,86],[8,87],[8,87],[8,87],[8,87],[8,88],[8,88],[8,88],[8,88],[8,89],[8,89],[8,89],[8,89],[8,90],[8,90],[8,90],[8,90],[8,91],[8,91],[8,91],[8,91],[8,92],[8,92],[8,92],[8,92],[8,93],[8,93],[8,93],[8,93],[8,94],[8,94],[8,94],[8,94],[8,95],[8,95],[8,95],[8,95],[8,96],[8,96],[8,96],[8,96],[8,97],[8,97],[8,97],[8,97],[8,98],[8,98],[8,98],[8,98],[8,99],[8,99],[8,99],[8,99],[8,100],[8,100],[8,100],[8,100],[8,101],[8,101],[8,101],[8,101],[8,102],[8,102],[8,102],[8,102],[8,103],[8,103],[8,103],[8,103],[8,104],[8,104],[8,104],[8,104],[8,105],[8,105],[8,105],[8,105],[8,106],[8,106],[8,106],[8,106],[8,107],[8,107],[8,107],[8,107],[8,108],[8,108],[8,108],[8,108],[8,109],[8,109],[8,109],[8,109],[8,110],[8,110],[8,110],[8,110],[8,111],[8,111],[8,111],[8,111],[8,112],[8,112],[8,112],[8,112],[8,113],[8,113],[8,113],[8,113],[8,114],[8,114],[8,114],[8,114],[8,115],[8,115],[8,115],[8,115],[8,116],[8,116],[8,116],[8,116],[8,117],[8,117],[8,117],[8,117],[8,118],[8,118],[8,118],[8,118],[8,119],[8,119],[8,119],[8,119],[8,120],[8,120],[8,120],[8,120],[8,121],[8,121],[8,121],[8,121],[8,122],[8,122],[8,122],[8,122],[8,123],[8,123],[8,123],[8,123],[8,124],[8,124],[8,124],[8,124],[8,125],[8,125],[8,125],[8,125],[8,126],[8,126],[8,126],[8,126],[8,127],[8,127],[8,127],[8,127],[8,128],[8,128],[8,128],[8,128],[8,129],[8,129],[8,129],[8,129],[8,130],[8,130],[8,130],[8,130],[8,131],[8,131],[8,131],[8,131],[8,132],[8,132],[8,132],[8,132],[8,133],[8,133],[8,133],[8,133],[8,134],[8,134],[8,134],[8,134],[8,135],[8,135],[8,135],[8,135],[8,136],[8,136],[8,136],[8,136],[8,137],[8,137],[8,137],[8,137],[8,138],[8,138],[8,138],[8,138],[8,139],[8,139],[8,139],[8,139],[8,140],[8,140],[8,140],[8,140],[8,141],[8,141],[8,141],[8,141],[8,142],[8,142],[8,142],[8,142],[8,143],[8,143],[8,143],[8,143],[8,144],[8,144],[8,144],[8,144],[8,145],[8,145],[8,145],[8,145],[8,146],[8,146],[8,146],[8,146],[8,147],[8,147],[8,147],[8,147],[8,148],[8,148],[8,148],[8,148],[8,149],[8,149],[8,149],[8,149],[8,150],[8,150],[8,150],[8,150],[8,151],[8,151],[8,151],[8,151],[8,152],[8,152],[8,152],[8,152],[8,153],[8,153],[8,153],[8,153],[8,154],[8,154],[8,154],[8,154],[8,155],[8,155],[8,155],[8,155],[8,156],[8,156],[8,156],[8,156],[8,157],[8,157],[8,157],[8,157],[8,158],[8,158],[8,158],[8,158],[8,159],[8,159],[8,159],[8,159],[8,160],[8,160],[8,160],[8,160],[8,161],[8,161],[8,161],[8,161],[8,162],[8,162],[8,162],[8,162],[8,163],[8,163],[8,163],[8,163],[8,164],[8,164],[8,164],[8,164],[8,165],[8,165],[8,165],[8,165],[8,166],[8,166],[8,166],[8,166],[8,167],[8,167],[8,167],[8,167],[8,168],[8,168],[8,168],[8,168],[8,169],[8,169],[8,169],[8,169],[8,170],[8,170],[8,170],[8,170],[8,171],[8,171],[8,171],[8,171],[8,172],[8,172],[8,172],[8,172],[8,173],[8,173],[8,173],[8,173],[8,174],[8,174],[8,174],[8,174],[8,175],[8,175],[8,175],[8,175],[8,176],[8,176],[8,176],[8,176],[8,177],[8,177],[8,177],[8,177],[8,178],[8,178],[8,178],[8,178],[8,179],[8,179],[8,179],[8,179],[8,180],[8,180],[8,180],[8,180],[8,181],[8,181],[8,181],[8,181],[8,182],[8,182],[8,182],[8,182],[8,183],[8,183],[8,183],[8,183],[8,184],[8,184],[8,184],[8,184],[8,185],[8,185],[8,185],[8,185],[8,186],[8,186],[8,186],[8,186],[8,187],[8,187],[8,187],[8,187],[8,188],[8,188],[8,188],[8,188],[8,189],[8,189],[8,189],[8,189],[8,190],[8,190],[8,190],[8,190],[8,191],[8,191],[8,191],[8,191],[8,192],[8,192],[8,192],[8,192],[8,193],[8,193],[8,193],[8,193],[8,194],[8,194],[8,194],[8,194],[8,195],[8,195],[8,195],[8,195],[8,196],[8,196],[8,196],[8,196],[8,197],[8,197],[8,197],[8,197],[8,198],[8,198],[8,198],[8,198],[8,199],[8,199],[8,199],[8,199],[8,200],[8,200],[8,200],[8,200],[8,201],[8,201],[8,201],[8,201],[8,202],[8,202],[8,202],[8,202],[8,203],[8,203],[8,203],[8,203],[8,204],[8,204],[8,204],[8,204],[8,205],[8,205],[8,205],[8,205],[8,206],[8,206],[8,206],[8,206],[8,207],[8,207],[8,207],[8,207],[8,208],[8,208],[8,208],[8,208],[8,209],[8,209],[8,209],[8,209],[8,210],[8,210],[8,210],[8,210],[8,211],[8,211],[8,211],[8,211],[8,212],[8,212],[8,212],[8,212],[8,213],[8,213],[8,213],[8,213],[8,214],[8,214],[8,214],[8,214],[8,215],[8,215],[8,215],[8,215],[8,216],[8,216],[8,216],[8,216],[8,217],[8,217],[8,217],[8,217],[8,218],[8,218],[8,218],[8,218],[8,219],[8,219],[8,219],[8,219],[8,220],[8,220],[8,220],[8,220],[8,221],[8,221],[8,221],[8,221],[8,222],[8,222],[8,222],[8,222],[8,223],[8,223],[8,223],[8,223],[8,224],[8,224],[8,224],[8,224],[8,225],[8,225],[8,225],[8,225],[8,226],[8,226],[8,226],[8,226],[8,227],[8,227],[8,227],[8,227],[8,228],[8,228],[8,228],[8,228],[8,229],[8,229],[8,229],[8,229],[8,230],[8,230],[8,230],[8,230],[8,231],[8,231],[8,231],[8,231],[8,232],[8,232],[8,232],[8,232],[8,233],[8,233],[8,233],[8,233],[8,234],[8,234],[8,234],[8,234],[8,235],[8,235],[8,235],[8,235],[8,236],[8,236],[8,236],[8,236],[8,237],[8,237],[8,237],[8,237],[8,238],[8,238],[8,238],[8,238],[8,239],[8,239],[8,239],[8,239],[8,240],[8,240],[8,240],[8,240],[8,241],[8,241],[8,241],[8,241],[8,242],[8,242],[8,242],[8,242],[8,243],[8,243],[8,243],[8,243],[8,244],[8,244],[8,244],[8,244],[8,245],[8,245],[8,245],[8,245],[8,246],[8,246],[8,246],[8,246],[8,247],[8,247],[8,247],[8,247],[8,248],[8,248],[8,248],[8,248],[8,249],[8,249],[8,249],[8,249],[8,250],[8,250],[8,250],[8,250],[8,251],[8,251],[8,251],[8,251],[8,252],[8,252],[8,252],[8,252],[8,253],[8,253],[8,253],[8,253],[8,254],[8,254],[8,254],[8,254],[8,255],[8,255],[8,255],[8,255],[8,256],[8,256],[8,256],[8,256],[8,257],[8,257],[8,257],[8,257],[8,258],[8,258],[8,258],[8,258],[8,259],[8,259],[8,259],[8,259],[8,260],[8,260],[8,260],[8,260],[8,261],[8,261],[8,261],[8,261],[8,262],[8,262],[8,262],[8,262],[8,263],[8,263],[8,263],[8,263],[8,264],[8,264],[8,264],[8,264],[8,265],[8,265],[8,265],[8,265],[8,266],[8,266],[8,266],[8,266],[8,267],[8,267],[8,267],[8,267],[8,268],[8,268],[8,268],[8,268],[8,269],[8,269],[8,269],[8,269],[8,270],[8,270],[8,270],[8,270],[8,271],[8,271],[8,271],[8,271],[8,272],[8,272],[8,272],[8,272],[8,273],[8,273],[8,273],[8,273],[8,274],[8,274],[8,274],[8,274],[8,275],[8,275],[8,275],[8,275],[8,276],[8,276],[8,276],[8,276],[8,277],[8,277],[8,277],[8,277],[8,278],[8,278],[8,278],[8,278],[8,279],[8,279],[8,279],[8,279],[8,280],[8,280],[8,280],[8,280],[8,281],[8,281],[8,281],[8,281],[8,282],[8,282],[8,282],[8,282],[8,283],[8,283],[8,283],[8,283],[8,284],[8,284],[8,284],[8,284],[8,285],[8,285],[8,285],[8,285],[8,286],[8,286],[8,286],[8,286],[8,287],[8,287],[8,287],[8,287],[8,288],[8,288],[8,288],[8,288],[8,289],[8,289],[8,289],[8,289],[8,290],[8,290],[8,290],[8,290],[8,291],[8,291],[8,291],[8,291],[8,292],[8,292],[8,292],[8,292],[8,293],[8,293],[8,293],[8,293],[8,294],[8,294],[8,294],[8,294],[8,295],[8,295],[8,295],[8,295],[8,296],[8,296],[8,296],[8,296],[8,297],[8,297],[8,297],[8,297],[8,298],[8,298],[8,298],[8,298],[8,299],[8,299],[8,299],[8,299],[8,300],[8,300],[8,300],[8,300],[8,301],[8,301],[8,301],[8,301],[8,302],[8,302],[8,302],[8,302],[8,303],[8,303],[8,303],[8,303],[8,304],[8,304],[8,304],[8,304],[8,305],[8,305],[8,305],[8,305],[8,306],[8,306],[8,306],[8,306],[8,307],[8,307],[8,307],[8,307],[8,308],[8,308],[8,308],[8,308],[8,309],[8,309],[8,309],[8,309],[8,310],[8,310],[8,310],[8,310],[8,311],[8,311],[8,311],[8,311],[8,312],[8,312],[8,312],[8,312],[8,313],[8,313],[8,313],[8,313],[8,314],[8,314],[8,314],[8,314],[8,315],[8,315],[8,315],[8,315],[8,316],[8,316],[8,316],[8,316],[8,317],[8,317],[8,317],[8,317],[8,318],[8,318],[8,318],[8,318],[8,319],[8,319],[8,319],[8,319],[8,320],[8,320],[8,320],[8,320],[8,321],[8,321],[8,321],[8,321],[8,322],[8,322],[8,322],[8,322],[8,323],[8,323],[8,323],[8,323],[8,324],[8,324],[8,324],[8,324],[8,325],[8,325],[8,325],[8,325],[8,326],[8,326],[8,326],[8,326],[8,327],[8,327],[8,327],[8,327],[8,328],[8,328],[8,328],[8,328],[8,329],[8,329],[8,329],[8,329],[8,330],[8,330],[8,330],[8,330],[8,331],[8,331],[8,331],[8,331],[8,332],[8,332],[8,332],[8,332],[8,333],[8,333],[8,333],[8,333],[8,334],[8,334],[8,334],[8,334],[8,335],[8,335],[8,335],[8,335],[8,336],[8,336],[8,336],[8,336],[8,337],[8,337],[8,337],[8,337],[8,338],[8,338],[8,338],[8,338],[8,339],[8,339],[8,339],[8,339],[8,340],[8,340],[8,340],[8,340],[8,341],[8,341],[8,341],[8,341],[8,342],[8,342],[8,342],[8,342],[8,343],[8,343],[8,343],[8,343],[8,344],[8,344],[8,344],[8,344],[8,345],[8,345],[8,345],[8,345],[8,346],[8,346],[8,346],[8,346],[8,347],[8,347],[8,347],[8,347],[8,348],[8,348],[8,348],[8,348],[8,349],[8,349],[8,349],[8,349],[8,350],[8,350],[8,350],[8,350],[8,351],[8,351],[8,351],[8,351],[8,352],[8,352],[8,352],[8,352],[8,353],[8,353],[8,353],[8,353],[8,354],[8,354],[8,354],[8,354],[8,355],[8,355],[8,355],[8,355],[8,356],[8,356],[8,356],[8,356],[8,357],[8,357],[8,357],[8,357],[8,358],[8,358],[8,358],[8,358],[8,359],[8,359],[8,359],[8,359],[8,360],[8,360],[8,360],[8,360],[8,361],[8,361],[8,361],[8,361],[8,362],[8,362],[8,362],[8,362],[8,363],[8,363],[8,363],[8,363],[8,364],[8,364],[8,364],[8,364],[8,365],[8,365],[8,365],[8,365],[8,366],[8,366],[8,366],[8,366],[8,367],[8,367],[8,367],[8,367],[8,368],[8,368],[8,368],[8,368],[8,369],[8,369],[8,369],[8,369],[8,370],[8,370],[8,370],[8,370],[8,371],[8,371],[8,371],[8,371],[8,372],[8,372],[8,372],[8,372],[8,373],[8,373],[8,373],[8,373],[8,374],[8,374],[8,374],[8,374],[8,375],[8,375],[8,375],[8,375],[8,376],[8,376],[8,376],[8,376],[8,377],[8,377],[8,377],[8,377],[8,378],[8,378],[8,378],[8,378],[8,379],[8,379],[8,379],[8,379],[8,380],[8,380],[8,380],[8,380],[8,381],[8,381],[8,381],[8,381],[8,382],[8,382],[8,382],[8,382],[8,383],[8,383],[8,383],[8,383],[8,384],[8,384],[8,384],[8,384],[8,385],[8,385],[8,385],[8,385],[8,386],[8,386],[8,386],[8,386],[8,387],[8,387],[8,387],[8,387],[8,388],[8,388],[8,388],[8,388],[8,389],[8,389],[8,389],[8,389],[8,390],[8,390],[8,390],[8,390],[8,391],[8,391],[8,391],[8,391],[8,392],[8,392],[8,392],[8,392],[8,393],[8,393],[8,393],[8,393],[8,394],[8,394],[8,394],[8,394],[8,395],[8,395],[8,395],[8,395],[8,396],[8,396],[8,396],[8,396],[8,397],[8,397],[8,397],[8,397],[8,398],[8,398],[8,398],[8,398],[8,399],[8,399],[8,399],[8,399],[8,400],[8,400],[8,400],[8,400],[8,401],[8,401],[8,401],[8,401],[8,402],[8,402],[8,402],[8,402],[8,403],[8,403],[8,403],[8,403],[8,404],[8,404],[8,404],[8,404],[8,405],[8,405],[8,405],[8,405],[8,406],[8,406],[8,406],[8,406],[8,407],[8,407],[8,407],[8,407],[8,408],[8,408],[8,408],[8,408],[8,409],[8,409],[8,409],[8,409],[8,410],[8,410],[8,410],[8,410],[8,411],[8,411],[8,411],[8,411],[8,412],[8,412],[8,412],[8,412],[8,413],[8,413],[8,413],[8,413],[8,414],[8,414],[8,414],[8,414],[8,415],[8,415],[8,415],[8,415],[8,416],[8,416],[8,416],[8,416],[8,417],[8,417],[8,417],[8,417],[8,418],[8,418],[8,418],[8,418],[8,419],[8,419],[8,419],[8,419],[8,420],[8,420],[8,420],[8,420],[8,421],[8,421],[8,421],[8,421],[8,422],[8,422],[8,422],[8,422],[8,423],[8,423],[8,423],[8,423],[8,424],[8,424],[8,424],[8,424],[8,425],[8,425],[8,425],[8,425],[8,426],[8,426],[8,426],[8,426],[8,427],[8,427],[8,427],[8,427],[8,428],[8,428],[8,428],[8,428],[8,429],[8,429],[8,429],[8,429],[8,430],[8,430],[8,430],[8,430],[8,431],[8,431],[8,431],[8,431],[8,432],[8,432],[8,432],[8,432],[8,433],[8,433],[8,433],[8,433],[8,434],[8,434],[8,434],[8,434],[8,435],[8,435],[8,435],[8,435],[8,436],[8,436],[8,436],[8,436],[8,437],[8,437],[8,437],[8,437],[8,438],[8,438],[8,438],[8,438],[8,439],[8,439],[8,439],[8,439],[8,440],[8,440],[8,440],[8,440],[8,441],[8,441],[8,441],[8,441],[8,442],[8,442],[8,442],[8,442],[8,443],[8,443],[8,443],[8,443],[8,444],[8,444],[8,444],[8,444],[8,445],[8,445],[8,445],[8,445],[8,446],[8,446],[8,446],[8,446],[8,447],[8,447],[8,447],[8,447],[8,448],[8,448],[8,448],[8,448],[8,449],[8,449],[8,449],[8,449],[8,450],[8,450],[8,450],[8,450],[8,451],[8,451],[8,451],[8,451],[8,452],[8,452],[8,452],[8,452],[8,453],[8,453],[8,453],[8,453],[8,454],[8,454],[8,454],[8,454],[8,455],[8,455],[8,455],[8,455],[8,456],[8,456],[8,456],[8,456],[8,457],[8,457],[8,457],[8,457],[8,458],[8,458],[8,458],[8,458],[8,459],[8,459],[8,459],[8,459],[8,460],[8,460],[8,460],[8,460],[8,461],[8,461],[8,461],[8,461],[8,462],[8,462],[8,462],[8,462],[8,463],[8,463],[8,463],[8,463],[8,464],[8,464],[8,464],[8,464],[8,465],[8,465],[8,465],[8,465],[8,466],[8,466],[8,466],[8,466],[8,467],[8,467],[8,467],[8,467],[8,468],[8,468],[8,468],[8,468],[8,469],[8,469],[8,469],[8,469],[8,470],[8,470],[8,470],[8,470],[8,471],[8,471],[8,471],[8,471],[8,472],[8,472],[8,472],[8,472],[8,473],[8,473],[8,473],[8,473],[8,474],[8,474],[8,474],[8,474],[8,475],[8,475],[8,475],[8,475],[8,476],[8,476],[8,476],[8,476],[8,477],[8,477],[8,477],[8,477],[8,478],[8,478],[8,478],[8,478],[8,479],[8,479],[8,479],[8,479],[8,480],[8,480],[8,480],[8,480],[8,481],[8,481],[8,481],[8,481],[8,482],[8,482],[8,482],[8,482],[8,483],[8,483],[8,483],[8,483],[8,484],[8,484],[8,484],[8,484],[8,485],[8,485],[8,485],[8,485],[8,486],[8,486],[8,486],[8,486],[8,487],[8,487],[8,487],[8,487],[8,488],[8,488],[8,488],[8,488],[8,489],[8,489],[8,489],[8,489],[8,490],[8,490],[8,490],[8,490],[8,491],[8,491],[8,491],[8,491],[8,492],[8,492],[8,492],[8,492],[8,493],[8,493],[8,493],[8,493],[8,494],[8,494],[8,494],[8,494],[8,495],[8,495],[8,495],[8,495],[8,496],[8,496],[8,496],[8,496],[8,497],[8,497],[8,497],[8,497],[8,498],[8,498],[8,498],[8,498],[8,499],[8,499],[8,499],[8,499],[8,500],[8,500],[8,500],[8,500],[21,3],[21,4],[21,4],[21,4],[21,4]],\"12,10\":[[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10],[0,11],[0,12],[0,13],[0,14],[0,15],[0,16],[0,17],[0,18],[0,19],[0,20],[0,21],[0,22],[0,23],[0,24],[0,25],[0,26],[0,27],[0,28],[0,29],[0,30],[0,31],[0,32],[0,33],[0,34],[0,35],[0,36],[0,37],[0,38],[0,39],[0,40],[0,41],[0,42],[0,43],[0,44],[0,45],[0,46],[0,47],[0,48],[0,49],[0,50],[0,51],[0,52],[0,53],[0,54],[0,55],[0,56],[0,57],[0,58],[0,59],[0,60],[0,61],[0,62],[0,63],[0,64],[0,65],[0,66],[0,67],[0,68],[0,69],[0,70],[0,71],[0,72],[0,73],[0,74],[0,75],[0,76],[0,77],[0,78],[0,79],[0,80],[0,81],[0,82],[0,83],[0,84],[0,85],[0,86],[0,87],[0,88],[0,89],[0,90],[0,91],[0,92],[0,93],[0,94],[0,95],[0,96],[0,97],[0,98],[0,99],[0,100],[0,101],[0,102],[0,103],[0,104],[0,105],[0,106],[0,107],[0,108],[0,109],[0,110],[0,111],[0,112],[0,113],[0,114],[0,115],[0,116],[0,117],[0,118],[0,119],[0,120],[0,121],[0,122],[0,123],[0,124],[0,125],[0,126],[0,127],[0,128],[0,129],[0,130],[0,131],[0,132],[0,133],[0,134],[0,135],[0,136],[0,137],[0,138],[0,139],[0,140],[0,141],[0,142],[0,143],[0,144],[0,145],[0,146],[0,147],[0,148],[0,149],[0,150],[0,151],[0,152],[0,153],[0,154],[0,155],[0,156],[0,157],[0,158],[0,159],[0,160],[0,161],[0,162],[0,163],[0,164],[0,165],[0,166],[0,167],[0,168],[0,169],[0,170],[0,171],[0,172],[0,173],[0,174],[0,175],[0,176],[0,177],[0,178],[0,179],[0,180],[0,181],[0,182],[0,183],[0,184],[0,185],[0,186],[0,187],[0,188],[0,189],[0,190],[0,191],[0,192],[0,193],[0,194],[0,195],[0,196],[0,197],[0,198],[0,199],[0,200],[0,201],[0,202],[0,203],[0,204],[0,205],[0,206],[0,207],[0,208],[0,209],[0,210],[0,211],[0,212],[0,213],[0,214],[0,215],[0,216],[0,217],[0,218],[0,219],[0,220],[0,221],[0,222],[0,223],[0,224],[0,225],[0,226],[0,227],[0,228],[0,229],[0,230],[0,231],[0,232],[0,233],[0,234],[0,235],[0,236],[0,237],[0,238],[0,239],[0,240],[0,241],[0,242],[0,243],[0,244],[0,245],[0,246],[0,247],[0,248],[0,249],[0,250],[0,251],[0,252],[0,253],[0,254],[0,255],[0,256],[0,257],[0,258],[0,259],[0,260],[0,261],[0,262],[0,263],[0,264],[0,265],[0,266],[0,267],[0,268],[0,269],[0,270],[0,271],[0,272],[0,273],[0,274],[0,275],[0,276],[0,277],[0,278],[0,279],[0,280],[0,281],[0,282],[0,283],[0,284],[0,285],[0,286],[0,287],[0,288],[0,289],[0,290],[0,291],[0,292],[0,293],[0,294],[0,295],[0,296],[0,297],[0,298],[0,299],[0,300],[0,301],[0,302],[0,303],[0,304],[0,305],[0,306],[0,307],[0,308],[0,309],[0,310],[0,311],[0,312],[0,313],[0,314],[0,315],[0,316],[0,317],[0,318],[0,319],[0,320],[0,321],[0,322],[0,323],[0,324],[0,325],[0,326],[0,327],[0,328],[0,329],[0,330],[0,331],[0,332],[0,333],[0,334],[0,335],[0,336],[0,337],[0,338],[0,339],[0,340],[0,341],[0,342],[0,343],[0,344],[0,345],[0,346],[0,347],[0,348],[0,349],[0,350],[0,351],[0,352],[0,353],[0,354],[0,355],[0,356],[0,357],[0,358],[0,359],[0,360],[0,361],[0,362],[0,363],[0,364],[0,365],[0,366],[0,367],[0,368],[0,369],[0,370],[0,371],[0,372],[0,373],[0,374],[0,375],[0,376],[0,377],[0,378],[0,379],[0,380],[0,381],[0,382],[0,383],[0,384],[0,385],[0,386],[0,387],[0,388],[0,389],[0,390],[0,391],[0,392],[0,393],[0,394],[0,395],[0,396],[0,397],[0,398],[0,399],[0,400],[0,401],[0,402],[0,403],[0,404],[0,405],[0,406],[0,407],[0,408],[0,409],[0,410],[0,411],[0,412],[0,413],[0,414],[0,415],[0,416],[0,417],[0,418],[0,419],[0,420],[0,421],[0,422],[0,423],[0,424],[0,425],[0,426],[0,427],[0,428],[0,429],[0,430],[0,431],[0,432],[0,433],[0,434],[0,435],[0,436],[0,437],[0,438],[0,439],[0,440],[0,441],[0,442],[0,443],[0,444],[0,445],[0,446],[0,447],[0,448],[0,449],[0,450],[0,451],[0,452],[0,453],[0,454],[0,455],[0,456],[0,457],[0,458],[0,459],[0,460],[0,461],[0,462],[0,463],[0,464],[0,465],[0,466],[0,467],[0,468],[0,469],[0,470],[0,471],[0,472],[0,473],[0,474],[0,475],[0,476],[0,477],[0,478],[0,479],[0,480],[0,481],[0,482],[0,483],[0,484],[0,485],[0,486],[0,487],[0,488],[0,489],[0,490],[0,491],[0,492],[0,493],[0,494],[0,495],[0,496],[0,497],[0,498],[0,499],[0,500],[1,2],[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],[1,9],[1,10],[1,11],[1,12],[1,13],[1,14],[1,15],[1,16],[1,17],[1,18],[1,19],[1,20],[1,21],[1,22],[1,23],[1,24],[1,25],[1,26],[1,27],[1,28],[1,29],[1,30],[1,31],[1,32],[1,33],[1,34],[1,35],[1,36],[1,37],[1,38],[1,39],[1,40],[1,41],[1,42],[1,43],[1,44],[1,45],[1,46],[1,47],[1,48],[1,49],[1,50],[1,51],[1,52],[1,53],[1,54],[1,55],[1,56],[1,57],[1,58],[1,59],[1,60],[1,61],[1,62],[1,63],[1,64],[1,65],[1,66],[1,67],[1,68],[1,69],[1,70],[1,71],[1,72],[1,73],[1,74],[1,75],[1,76],[1,77],[1,78],[1,79],[1,80],[1,81],[1,82],[1,83],[1,84],[1,85],[1,86],[1,87],[1,88],[1,89],[1,90],[1,91],[1,92],[1,93],[1,94],[1,95],[1,96],[1,97],[1,98],[1,99],[1,100],[1,101],[1,102],[1,103],[1,104],[1,105],[1,106],[1,107],[1,108],[1,109],[1,110],[1,111],[1,112],[1,113],[1,114],[1,115],[1,116],[1,117],[1,118],[1,119],[1,120],[1,121],[1,122],[1,123],[1,124],[1,125],[1,126],[1,127],[1,128],[1,129],[1,130],[1,131],[1,132],[1,133],[1,134],[1,135],[1,136],[1,137],[1,138],[1,139],[1,140],[1,141],[1,142],[1,143],[1,144],[1,145],[1,146],[1,147],[1,148],[1,149],[1,150],[1,151],[1,152],[1,153],[1,154],[1,155],[1,156],[1,157],[1,158],[1,159],[1,160],[1,161],[1,162],[1,163],[1,164],[1,165],[1,166],[1,167],[1,168],[1,169],[1,170],[1,171],[1,172],[1,173],[1,174],[1,175],[1,176],[1,177],[1,178],[1,179],[1,180],[1,181],[1,182],[1,183],[1,184],[1,185],[1,186],[1,187],[1,188],[1,189],[1,190],[1,191],[1,192],[1,193],[1,194],[1,195],[1,196],[1,197],[1,198],[1,199],[1,200],[1,201],[1,202],[1,203],[1,204],[1,205],[1,206],[1,207],[1,208],[1,209],[1,210],[1,211],[1,212],[1,213],[1,214],[1,215],[1,216],[1,217],[1,218],[1,219],[1,220],[1,221],[1,222],[1,223],[1,224],[1,225],[1,226],[1,227],[1,228],[1,229],[1,230],[1,231],[1,232],[1,233],[1,234],[1,235],[1,236],[1,237],[1,238],[1,239],[1,240],[1,241],[1,242],[1,243],[1,244],[1,245],[1,246],[1,247],[1,248],[1,249],[1,250],[1,251],[1,252],[1,253],[1,254],[1,255],[1,256],[1,257],[1,258],[1,259],[1,260],[1,261],[1,262],[1,263],[1,264],[1,265],[1,266],[1,267],[1,268],[1,269],[1,270],[1,271],[1,272],[1,273],[1,274],[1,275],[1,276],[1,277],[1,278],[1,279],[1,280],[1,281],[1,282],[1,283],[1,284],[1,285],[1,286],[1,287],[1,288],[1,289],[1,290],[1,291],[1,292],[1,293],[1,294],[1,295],[1,296],[1,297],[1,298],[1,299],[1,300],[1,301],[1,302],[1,303],[1,304],[1,305],[1,306],[1,307],[1,308],[1,309],[1,310],[1,311],[1,312],[1,313],[1,314],[1,315],[1,316],[1,317],[1,318],[1,319],[1,320],[1,321],[1,322],[1,323],[1,324],[1,325],[1,326],[1,327],[1,328],[1,329],[1,330],[1,331],[1,332],[1,333],[1,334],[1,335],[1,336],[1,337],[1,338],[1,339],[1,340],[1,341],[1,342],[1,343],[1,344],[1,345],[1,346],[1,347],[1,348],[1,349],[1,350],[1,351],[1,352],[1,353],[1,354],[1,355],[1,356],[1,357],[1,358],[1,359],[1,360],[1,361],[1,362],[1,363],[1,364],[1,365],[1,366],[1,367],[1,368],[1,369],[1,370],[1,371],[1,372],[1,373],[1,374],[1,375],[1,376],[1,377],[1,378],[1,379],[1,380],[1,381],[1,382],[1,383],[1,384],[1,385],[1,386],[1,387],[1,388],[1,389],[1,390],[1,391],[1,392],[1,393],[1,394],[1,395],[1,396],[1,397],[1,398],[1,399],[1,400],[1,401],[1,402],[1,403],[1,404],[1,405],[1,406],[1,407],[1,408],[1,409],[1,410],[1,411],[1,412],[1,413],[1,414],[1,415],[1,416],[1,417],[1,418],[1,419],[1,420],[1,421],[1,422],[1,423],[1,424],[1,425],[1,426],[1,427],[1,428],[1,429],[1,430],[1,431],[1,432],[1,433],[1,434],[1,435],[1,436],[1,437],[1,438],[1,439],[1,440],[1,441],[1,442],[1,443],[1,444],[1,445],[1,446],[1,447],[1,448],[1,449],[1,450],[1,451],[1,452],[1,453],[1,454],[1,455],[1,456],[1,457],[1,458],[1,459],[1,460],[1,461],[1,462],[1,463],[1,464],[1,465],[1,466],[1,467],[1,468],[1,469],[1,470],[1,471],[1,472],[1,473],[1,474],[1,475],[1,476],[1,477],[1,478],[1,479],[1,480],[1,481],[1,482],[1,483],[1,484],[1,485],[1,486],[1,487],[1,488],[1,489],[1,490],[1,491],[1,492],[1,493],[1,494],[1,495],[1,496],[1,497],[1,498],[1,499],[1,500],[2,2],[2,3],[2,4],[2,5],[2,6],[2,7],[2,8],[2,9],[2,10],[2,11],[2,12],[2,13],[2,14],[2,15],[2,16],[2,17],[2,18],[2,19],[2,20],[2,21],[2,22],[2,23],[2,24],[2,25],[2,26],[2,27],[2,28],[2,29],[2,30],[2,31],[2,32],[2,33],[2,34],[2,35],[2,36],[2,37],[2,38],[2,39],[2,40],[2,41],[2,42],[2,43],[2,44],[2,45],[2,46],[2,47],[2,48],[2,49],[2,50],[2,51],[2,52],[2,53],[2,54],[2,55],[2,56],[2,57],[2,58],[2,59],[2,60],[2,61],[2,62],[2,63],[2,64],[2,65],[2,66],[2,67],[2,68],[2,69],[2,70],[2,71],[2,72],[2,73],[2,74],[2,75],[2,76],[2,77],[2,78],[2,79],[2,80],[2,81],[2,82],[2,83],[2,84],[2,85],[2,86],[2,87],[2,88],[2,89],[2,90],[2,91],[2,92],[2,93],[2,94],[2,95],[2,96],[2,97],[2,98],[2,99],[2,100],[2,101],[2,102],[2,103],[2,104],[2,105],[2,106],[2,107],[2,108],[2,109],[2,110],[2,111],[2,112],[2,113],[2,114],[2,115],[2,116],[2,117],[2,118],[2,119],[2,120],[2,121],[2,122],[2,123],[2,124],[2,125],[2,126],[2,127],[2,128],[2,129],[2,130],[2,131],[2,132],[2,133],[2,134],[2,135],[2,136],[2,137],[2,138],[2,139],[2,140],[2,141],[2,142],[2,143],[2,144],[2,145],[2,146],[2,147],[2,148],[2,149],[2,150],[2,151],[2,152],[2,153],[2,154],[2,155],[2,156],[2,157],[2,158],[2,159],[2,160],[2,161],[2,162],[2,163],[2,164],[2,165],[2,166],[2,167],[2,168],[2,169],[2,170],[2,171],[2,172],[2,173],[2,174],[2,175],[2,176],[2,177],[2,178],[2,179],[2,180],[2,181],[2,182],[2,183],[2,184],[2,185],[2,186],[2,187],[2,188],[2,189],[2,190],[2,191],[2,192],[2,193],[2,194],[2,195],[2,196],[2,197],[2,198],[2,199],[2,200],[2,201],[2,202],[2,203],[2,204],[2,205],[2,206],[2,207],[2,208],[2,209],[2,210],[2,211],[2,212],[2,213],[2,214],[2,215],[2,216],[2,217],[2,218],[2,219],[2,220],[2,221],[2,222],[2,223],[2,224],[2,225],[2,226],[2,227],[2,228],[2,229],[2,230],[2,231],[2,232],[2,233],[2,234],[2,235],[2,236],[2,237],[2,238],[2,239],[2,240],[2,241],[2,242],[2,243],[2,244],[2,245],[2,246],[2,247],[2,248],[2,249],[2,250],[2,251],[2,252],[2,253],[2,254],[2,255],[2,256],[2,257],[2,258],[2,259],[2,260],[2,261],[2,262],[2,263],[2,264],[2,265],[2,266],[2,267],[2,268],[2,269],[2,270],[2,271],[2,272],[2,273],[2,274],[2,275],[2,276],[2,277],[2,278],[2,279],[2,280],[2,281],[2,282],[2,283],[2,284],[2,285],[2,286],[2,287],[2,288],[2,289],[2,290],[2,291],[2,292],[2,293],[2,294],[2,295],[2,296],[2,297],[2,298],[2,299],[2,300],[2,301],[2,302],[2,303],[2,304],[2,305],[2,306],[2,307],[2,308],[2,309],[2,310],[2,311],[2,312],[2,313],[2,314],[2,315],[2,316],[2,317],[2,318],[2,319],[2,320],[2,321],[2,322],[2,323],[2,324],[2,325],[2,326],[2,327],[2,328],[2,329],[2,330],[2,331],[2,332],[2,333],[2,334],[2,335],[2,336],[2,337],[2,338],[2,339],[2,340],[2,341],[2,342],[2,343],[2,344],[2,345],[2,346],[2,347],[2,348],[2,349],[2,350],[2,351],[2,352],[2,353],[2,354],[2,355],[2,356],[2,357],[2,358],[2,359],[2,360],[2,361],[2,362],[2,363],[2,364],[2,365],[2,366],[2,367],[2,368],[2,369],[2,370],[2,371],[2,372],[2,373],[2,374],[2,375],[2,376],[2,377],[2,378],[2,379],[2,380],[2,381],[2,382],[2,383],[2,384],[2,385],[2,386],[2,387],[2,388],[2,389],[2,390],[2,391],[2,392],[2,393],[2,394],[2,395],[2,396],[2,397],[2,398],[2,399],[2,400],[2,401],[2,402],[2,403],[2,404],[2,405],[2,406],[2,407],[2,408],[2,409],[2,410],[2,411],[2,412],[2,413],[2,414],[2,415],[2,416],[2,417],[2,418],[2,419],[2,420],[2,421],[2,422],[2,423],[2,424],[2,425],[2,426],[2,427],[2,428],[2,429],[2,430],[2,431],[2,432],[2,433],[2,434],[2,435],[2,436],[2,437],[2,438],[2,439],[2,440],[2,441],[2,442],[2,443],[2,444],[2,445],[2,446],[2,447],[2,448],[2,449],[2,450],[2,451],[2,452],[2,453],[2,454],[2,455],[2,456],[2,457],[2,458],[2,459],[2,460],[2,461],[2,462],[2,463],[2,464],[2,465],[2,466],[2,467],[2,468],[2,469],[2,470],[2,471],[2,472],[2,473],[2,474],[2,475],[2,476],[2,477],[2,478],[2,479],[2,480],[2,481],[2,482],[2,483],[2,484],[2,485],[2,486],[2,487],[2,488],[2,489],[2,490],[2,491],[2,492],[2,493],[2,494],[2,495],[2,496],[2,497],[2,498],[2,499],[2,500],[3,2],[3,3],[3,4],[3,5],[3,6],[3,7],[3,8],[3,9],[3,10],[3,11],[3,12],[3,13],[3,14],[3,15],[3,16],[3,17],[3,18],[3,19],[3,20],[3,21],[3,22],[3,23],[3,24],[3,25],[3,26],[3,27],[3,28],[3,29],[3,30],[3,31],[3,32],[3,33],[3,34],[3,35],[3,36],[3,37],[3,38],[3,39],[3,40],[3,41],[3,42],[3,43],[3,44],[3,45],[3,46],[3,47],[3,48],[3,49],[3,50],[3,51],[3,52],[3,53],[3,54],[3,55],[3,56],[3,57],[3,58],[3,59],[3,60],[3,61],[3,62],[3,63],[3,64],[3,65],[3,66],[3,67],[3,68],[3,69],[3,70],[3,71],[3,72],[3,73],[3,74],[3,75],[3,76],[3,77],[3,78],[3,79],[3,80],[3,81],[3,82],[3,83],[3,84],[3,85],[3,86],[3,87],[3,88],[3,89],[3,90],[3,91],[3,92],[3,93],[3,94],[3,95],[3,96],[3,97],[3,98],[3,99],[3,100],[3,101],[3,102],[3,103],[3,104],[3,105],[3,106],[3,107],[3,108],[3,109],[3,110],[3,111],[3,112],[3,113],[3,114],[3,115],[3,116],[3,117],[3,118],[3,119],[3,120],[3,121],[3,122],[3,123],[3,124],[3,125],[3,126],[3,127],[3,128],[3,129],[3,130],[3,131],[3,132],[3,133],[3,134],[3,135],[3,136],[3,137],[3,138],[3,139],[3,140],[3,141],[3,142],[3,143],[3,144],[3,145],[3,146],[3,147],[3,148],[3,149],[3,150],[3,151],[3,152],[3,153],[3,154],[3,155],[3,156],[3,157],[3,158],[3,159],[3,160],[3,161],[3,162],[3,163],[3,164],[3,165],[3,166],[3,167],[3,168],[3,169],[3,170],[3,171],[3,172],[3,173],[3,174],[3,175],[3,176],[3,177],[3,178],[3,179],[3,180],[3,181],[3,182],[3,183],[3,184],[3,185],[3,186],[3,187],[3,188],[3,189],[3,190],[3,191],[3,192],[3,193],[3,194],[3,195],[3,196],[3,197],[3,198],[3,199],[3,200],[3,201],[3,202],[3,203],[3,204],[3,205],[3,206],[3,207],[3,208],[3,209],[3,210],[3,211],[3,212],[3,213],[3,214],[3,215],[3,216],[3,217],[3,218],[3,219],[3,220],[3,221],[3,222],[3,223],[3,224],[3,225],[3,226],[3,227],[3,228],[3,229],[3,230],[3,231],[3,232],[3,233],[3,234],[3,235],[3,236],[3,237],[3,238],[3,239],[3,240],[3,241],[3,242],[3,243],[3,244],[3,245],[3,246],[3,247],[3,248],[3,249],[3,250],[3,251],[3,252],[3,253],[3,254],[3,255],[3,256],[3,257],[3,258],[3,259],[3,260],[3,261],[3,262],[3,263],[3,264],[3,265],[3,266],[3,267],[3,268],[3,269],[3,270],[3,271],[3,272],[3,273],[3,274],[3,275],[3,276],[3,277],[3,278],[3,279],[3,280],[3,281],[3,282],[3,283],[3,284],[3,285],[3,286],[3,287],[3,288],[3,289],[3,290],[3,291],[3,292],[3,293],[3,294],[3,295],[3,296],[3,297],[3,298],[3,299],[3,300],[3,301],[3,302],[3,303],[3,304],[3,305],[3,306],[3,307],[3,308],[3,309],[3,310],[3,311],[3,312],[3,313],[3,314],[3,315],[3,316],[3,317],[3,318],[3,319],[3,320],[3,321],[3,322],[3,323],[3,324],[3,325],[3,326],[3,327],[3,328],[3,329],[3,330],[3,331],[3,332],[3,333],[3,334],[3,335],[3,336],[3,337],[3,338],[3,339],[3,340],[3,341],[3,342],[3,343],[3,344],[3,345],[3,346],[3,347],[3,348],[3,349],[3,350],[3,351],[3,352],[3,353],[3,354],[3,355],[3,356],[3,357],[3,358],[3,359],[3,360],[3,361],[3,362],[3,363],[3,364],[3,365],[3,366],[3,367],[3,368],[3,369],[3,370],[3,371],[3,372],[3,373],[3,374],[3,375],[3,376],[3,377],[3,378],[3,379],[3,380],[3,381],[3,382],[3,383],[3,384],[3,385],[3,386],[3,387],[3,388],[3,389],[3,390],[3,391],[3,392],[3,393],[3,394],[3,395],[3,396],[3,397],[3,398],[3,399],[3,400],[3,401],[3,402],[3,403],[3,404],[3,405],[3,406],[3,407],[3,408],[3,409],[3,410],[3,411],[3,412],[3,413],[3,414],[3,415],[3,416],[3,417],[3,418],[3,419],[3,420],[3,421],[3,422],[3,423],[3,424],[3,425],[3,426],[3,427],[3,428],[3,429],[3,430],[3,431],[3,432],[3,433],[3,434],[3,435],[3,436],[3,437],[3,438],[3,439],[3,440],[3,441],[3,442],[3,443],[3,444],[3,445],[3,446],[3,447],[3,448],[3,449],[3,450],[3,451],[3,452],[3,453],[3,454],[3,455],[3,456],[3,457],[3,458],[3,459],[3,460],[3,461],[3,462],[3,463],[3,464],[3,465],[3,466],[3,467],[3,468],[3,469],[3,470],[3,471],[3,472],[3,473],[3,474],[3,475],[3,476],[3,477],[3,478],[3,479],[3,480],[3,481],[3,482],[3,483],[3,484],[3,485],[3,486],[3,487],[3,488],[3,489],[3,490],[3,491],[3,492],[3,493],[3,494],[3,495],[3,496],[3,497],[3,498],[3,499],[3,500],[4,2],[4,3],[4,4],[4,5],[4,6],[4,7],[4,8],[4,9],[4,10],[4,11],[4,12],[4,13],[4,14],[4,15],[4,16],[4,17],[4,18],[4,19],[4,20],[4,21],[4,22],[4,23],[4,24],[4,25],[4,26],[4,27],[4,28],[4,29],[4,30],[4,31],[4,32],[4,33],[4,34],[4,35],[4,36],[4,37],[4,38],[4,39],[4,40],[4,41],[4,42],[4,43],[4,44],[4,45],[4,46],[4,47],[4,48],[4,49],[4,50],[4,51],[4,52],[4,53],[4,54],[4,55],[4,56],[4,57],[4,58],[4,59],[4,60],[4,61],[4,62],[4,63],[4,64],[4,65],[4,66],[4,67],[4,68],[4,69],[4,70],[4,71],[4,72],[4,73],[4,74],[4,75],[4,76],[4,77],[4,78],[4,79],[4,80],[4,81],[4,82],[4,83],[4,84],[4,85],[4,86],[4,87],[4,88],[4,89],[4,90],[4,91],[4,92],[4,93],[4,94],[4,95],[4,96],[4,97],[4,98],[4,99],[4,100],[4,101],[4,102],[4,103],[4,104],[4,105],[4,106],[4,107],[4,108],[4,109],[4,110],[4,111],[4,112],[4,113],[4,114],[4,115],[4,116],[4,117],[4,118],[4,119],[4,120],[4,121],[4,122],[4,123],[4,124],[4,125],[4,126],[4,127],[4,128],[4,129],[4,130],[4,131],[4,132],[4,133],[4,134],[4,135],[4,136],[4,137],[4,138],[4,139],[4,140],[4,141],[4,142],[4,143],[4,144],[4,145],[4,146],[4,147],[4,148],[4,149],[4,150],[4,151],[4,152],[4,153],[4,154],[4,155],[4,156],[4,157],[4,158],[4,159],[4,160],[4,161],[4,162],[4,163],[4,164],[4,165],[4,166],[4,167],[4,168],[4,169],[4,170],[4,171],[4,172],[4,173],[4,174],[4,175],[4,176],[4,177],[4,178],[4,179],[4,180],[4,181],[4,182],[4,183],[4,184],[4,185],[4,186],[4,187],[4,188],[4,189],[4,190],[4,191],[4,192],[4,193],[4,194],[4,195],[4,196],[4,197],[4,198],[4,199],[4,200],[4,201],[4,202],[4,203],[4,204],[4,205],[4,206],[4,207],[4,208],[4,209],[4,210],[4,211],[4,212],[4,213],[4,214],[4,215],[4,216],[4,217],[4,218],[4,219],[4,220],[4,221],[4,222],[4,223],[4,224],[4,225],[4,226],[4,227],[4,228],[4,229],[4,230],[4,231],[4,232],[4,233],[4,234],[4,235],[4,236],[4,237],[4,238],[4,239],[4,240],[4,241],[4,242],[4,243],[4,244],[4,245],[4,246],[4,247],[4,248],[4,249],[4,250],[4,251],[4,252],[4,253],[4,254],[4,255],[4,256],[4,257],[4,258],[4,259],[4,260],[4,261],[4,262],[4,263],[4,264],[4,265],[4,266],[4,267],[4,268],[4,269],[4,270],[4,271],[4,272],[4,273],[4,274],[4,275],[4,276],[4,277],[4,278],[4,279],[4,280],[4,281],[4,282],[4,283],[4,284],[4,285],[4,286],[4,287],[4,288],[4,289],[4,290],[4,291],[4,292],[4,293],[4,294],[4,295],[4,296],[4,297],[4,298],[4,299],[4,300],[4,301],[4,302],[4,303],[4,304],[4,305],[4,306],[4,307],[4,308],[4,309],[4,310],[4,311],[4,312],[4,313],[4,314],[4,315],[4,316],[4,317],[4,318],[4,319],[4,320],[4,321],[4,322],[4,323],[4,324],[4,325],[4,326],[4,327],[4,328],[4,329],[4,330],[4,331],[4,332],[4,333],[4,334],[4,335],[4,336],[4,337],[4,338],[4,339],[4,340],[4,341],[4,342],[4,343],[4,344],[4,345],[4,346],[4,347],[4,348],[4,349],[4,350],[4,351],[4,352],[4,353],[4,354],[4,355],[4,356],[4,357],[4,358],[4,359],[4,360],[4,361],[4,362],[4,363],[4,364],[4,365],[4,366],[4,367],[4,368],[4,369],[4,370],[4,371],[4,372],[4,373],[4,374],[4,375],[4,376],[4,377],[4,378],[4,379],[4,380],[4,381],[4,382],[4,383],[4,384],[4,385],[4,386],[4,387],[4,388],[4,389],[4,390],[4,391],[4,392],[4,393],[4,394],[4,395],[4,396],[4,397],[4,398],[4,399],[4,400],[4,401],[4,402],[4,403],[4,404],[4,405],[4,406],[4,407],[4,408],[4,409],[4,410],[4,411],[4,412],[4,413],[4,414],[4,415],[4,416],[4,417],[4,418],[4,419],[4,420],[4,421],[4,422],[4,423],[4,424],[4,425],[4,426],[4,427],[4,428],[4,429],[4,430],[4,431],[4,432],[4,433],[4,434],[4,435],[4,436],[4,437],[4,438],[4,439],[4,440],[4,441],[4,442],[4,443],[4,444],[4,445],[4,446],[4,447],[4,448],[4,449],[4,450],[4,451],[4,452],[4,453],[4,454],[4,455],[4,456],[4,457],[4,458],[4,459],[4,460],[4,461],[4,462],[4,463],[4,464],[4,465],[4,466],[4,467],[4,468],[4,469],[4,470],[4,471],[4,472],[4,473],[4,474],[4,475],[4,476],[4,477],[4,478],[4,479],[4,480],[4,481],[4,482],[4,483],[4,484],[4,485],[4,486],[4,487],[4,488],[4,489],[4,490],[4,491],[4,492],[4,493],[4,494],[4,495],[4,496],[4,497],[4,498],[4,499],[4,500],[5,2],[5,3],[5,4],[5,5],[5,6],[5,7],[5,8],[5,9],[5,10],[5,11],[5,12],[5,13],[5,14],[5,15],[5,16],[5,17],[5,18],[5,19],[5,20],[5,21],[5,22],[5,23],[5,24],[5,25],[5,26],[5,27],[5,28],[5,29],[5,30],[5,31],[5,32],[5,33],[5,34],[5,35],[5,36],[5,37],[5,38],[5,39],[5,40],[5,41],[5,42],[5,43],[5,44],[5,45],[5,46],[5,47],[5,48],[5,49],[5,50],[5,51],[5,52],[5,53],[5,54],[5,55],[5,56],[5,57],[5,58],[5,59],[5,60],[5,61],[5,62],[5,63],[5,64],[5,65],[5,66],[5,67],[5,68],[5,69],[5,70],[5,71],[5,72],[5,73],[5,74],[5,75],[5,76],[5,77],[5,78],[5,79],[5,80],[5,81],[5,82],[5,83],[5,84],[5,85],[5,86],[5,87],[5,88],[5,89],[5,90],[5,91],[5,92],[5,93],[5,94],[5,95],[5,96],[5,97],[5,98],[5,99],[5,100],[5,101],[5,102],[5,103],[5,104],[5,105],[5,106],[5,107],[5,108],[5,109],[5,110],[5,111],[5,112],[5,113],[5,114],[5,115],[5,116],[5,117],[5,118],[5,119],[5,120],[5,121],[5,122],[5,123],[5,124],[5,125],[5,126],[5,127],[5,128],[5,129],[5,130],[5,131],[5,132],[5,133],[5,134],[5,135],[5,136],[5,137],[5,138],[5,139],[5,140],[5,141],[5,142],[5,143],[5,144],[5,145],[5,146],[5,147],[5,148],[5,149],[5,150],[5,151],[5,152],[5,153],[5,154],[5,155],[5,156],[5,157],[5,158],[5,159],[5,160],[5,161],[5,162],[5,163],[5,164],[5,165],[5,166],[5,167],[5,168],[5,169],[5,170],[5,171],[5,172],[5,173],[5,174],[5,175],[5,176],[5,177],[5,178],[5,179],[5,180],[5,181],[5,182],[5,183],[5,184],[5,185],[5,186],[5,187],[5,188],[5,189],[5,190],[5,191],[5,192],[5,193],[5,194],[5,195],[5,196],[5,197],[5,198],[5,199],[5,200],[5,201],[5,202],[5,203],[5,204],[5,205],[5,206],[5,207],[5,208],[5,209],[5,210],[5,211],[5,212],[5,213],[5,214],[5,215],[5,216],[5,217],[5,218],[5,219],[5,220],[5,221],[5,222],[5,223],[5,224],[5,225],[5,226],[5,227],[5,228],[5,229],[5,230],[5,231],[5,232],[5,233],[5,234],[5,235],[5,236],[5,237],[5,238],[5,239],[5,240],[5,241],[5,242],[5,243],[5,244],[5,245],[5,246],[5,247],[5,248],[5,249],[5,250],[5,251],[5,252],[5,253],[5,254],[5,255],[5,256],[5,257],[5,258],[5,259],[5,260],[5,261],[5,262],[5,263],[5,264],[5,265],[5,266],[5,267],[5,268],[5,269],[5,270],[5,271],[5,272],[5,273],[5,274],[5,275],[5,276],[5,277],[5,278],[5,279],[5,280],[5,281],[5,282],[5,283],[5,284],[5,285],[5,286],[5,287],[5,288],[5,289],[5,290],[5,291],[5,292],[5,293],[5,294],[5,295],[5,296],[5,297],[5,298],[5,299],[5,300],[5,301],[5,302],[5,303],[5,304],[5,305],[5,306],[5,307],[5,308],[5,309],[5,310],[5,311],[5,312],[5,313],[5,314],[5,315],[5,316],[5,317],[5,318],[5,319],[5,320],[5,321],[5,322],[5,323],[5,324],[5,325],[5,326],[5,327],[5,328],[5,329],[5,330],[5,331],[5,332],[5,333],[5,334],[5,335],[5,336],[5,337],[5,338],[5,339],[5,340],[5,341],[5,342],[5,343],[5,344],[5,345],[5,346],[5,347],[5,348],[5,349],[5,350],[5,351],[5,352],[5,353],[5,354],[5,355],[5,356],[5,357],[5,358],[5,359],[5,360],[5,361],[5,362],[5,363],[5,364],[5,365],[5,366],[5,367],[5,368],[5,369],[5,370],[5,371],[5,372],[5,373],[5,374],[5,375],[5,376],[5,377],[5,378],[5,379],[5,380],[5,381],[5,382],[5,383],[5,384],[5,385],[5,386],[5,387],[5,388],[5,389],[5,390],[5,391],[5,392],[5,393],[5,394],[5,395],[5,396],[5,397],[5,398],[5,399],[5,400],[5,401],[5,402],[5,403],[5,404],[5,405],[5,406],[5,407],[5,408],[5,409],[5,410],[5,411],[5,412],[5,413],[5,414],[5,415],[5,416],[5,417],[5,418],[5,419],[5,420],[5,421],[5,422],[5,423],[5,424],[5,425],[5,426],[5,427],[5,428],[5,429],[5,430],[5,431],[5,432],[5,433],[5,434],[5,435],[5,436],[5,437],[5,438],[5,439],[5,440],[5,441],[5,442],[5,443],[5,444],[5,445],[5,446],[5,447],[5,448],[5,449],[5,450],[5,451],[5,452],[5,453],[5,454],[5,455],[5,456],[5,457],[5,458],[5,459],[5,460],[5,461],[5,462],[5,463],[5,464],[5,465],[5,466],[5,467],[5,468],[5,469],[5,470],[5,471],[5,472],[5,473],[5,474],[5,475],[5,476],[5,477],[5,478],[5,479],[5,480],[5,481],[5,482],[5,483],[5,484],[5,485],[5,486],[5,487],[5,488],[5,489],[5,490],[5,491],[5,492],[5,493],[5,494],[5,495],[5,496],[5,497],[5,498],[5,499],[5,500],[6,2],[6,3],[6,4],[6,5],[6,6],[6,7],[6,8],[6,9],[6,10],[6,11],[6,12],[6,13],[6,14],[6,15],[6,16],[6,17],[6,18],[6,19],[6,20],[6,21],[6,22],[6,23],[6,24],[6,25],[6,26],[6,27],[6,28],[6,29],[6,30],[6,31],[6,32],[6,33],[6,34],[6,35],[6,36],[6,37],[6,38],[6,39],[6,40],[6,41],[6,42],[6,43],[6,44],[6,45],[6,46],[6,47],[6,48],[6,49],[6,50],[6,51],[6,52],[6,53],[6,54],[6,55],[6,56],[6,57],[6,58],[6,59],[6,60],[6,61],[6,62],[6,63],[6,64],[6,65],[6,66],[6,67],[6,68],[6,69],[6,70],[6,71],[6,72],[6,73],[6,74],[6,75],[6,76],[6,77],[6,78],[6,79],[6,80],[6,81],[6,82],[6,83],[6,84],[6,85],[6,86],[6,87],[6,88],[6,89],[6,90],[6,91],[6,92],[6,93],[6,94],[6,95],[6,96],[6,97],[6,98],[6,99],[6,100],[6,101],[6,102],[6,103],[6,104],[6,105],[6,106],[6,107],[6,108],[6,109],[6,110],[6,111],[6,112],[6,113],[6,114],[6,115],[6,116],[6,117],[6,118],[6,119],[6,120],[6,121],[6,122],[6,123],[6,124],[6,125],[6,126],[6,127],[6,128],[6,129],[6,130],[6,131],[6,132],[6,133],[6,134],[6,135],[6,136],[6,137],[6,138],[6,139],[6,140],[6,141],[6,142],[6,143],[6,144],[6,145],[6,146],[6,147],[6,148],[6,149],[6,150],[6,151],[6,152],[6,153],[6,154],[6,155],[6,156],[6,157],[6,158],[6,159],[6,160],[6,161],[6,162],[6,163],[6,164],[6,165],[6,166],[6,167],[6,168],[6,169],[6,170],[6,171],[6,172],[6,173],[6,174],[6,175],[6,176],[6,177],[6,178],[6,179],[6,180],[6,181],[6,182],[6,183],[6,184],[6,185],[6,186],[6,187],[6,188],[6,189],[6,190],[6,191],[6,192],[6,193],[6,194],[6,195],[6,196],[6,197],[6,198],[6,199],[6,200],[6,201],[6,202],[6,203],[6,204],[6,205],[6,206],[6,207],[6,208],[6,209],[6,210],[6,211],[6,212],[6,213],[6,214],[6,215],[6,216],[6,217],[6,218],[6,219],[6,220],[6,221],[6,222],[6,223],[6,224],[6,225],[6,226],[6,227],[6,228],[6,229],[6,230],[6,231],[6,232],[6,233],[6,234],[6,235],[6,236],[6,237],[6,238],[6,239],[6,240],[6,241],[6,242],[6,243],[6,244],[6,245],[6,246],[6,247],[6,248],[6,249],[6,250],[6,251],[6,252],[6,253],[6,254],[6,255],[6,256],[6,257],[6,258],[6,259],[6,260],[6,261],[6,262],[6,263],[6,264],[6,265],[6,266],[6,267],[6,268],[6,269],[6,270],[6,271],[6,272],[6,273],[6,274],[6,275],[6,276],[6,277],[6,278],[6,279],[6,280],[6,281],[6,282],[6,283],[6,284],[6,285],[6,286],[6,287],[6,288],[6,289],[6,290],[6,291],[6,292],[6,293],[6,294],[6,295],[6,296],[6,297],[6,298],[6,299],[6,300],[6,301],[6,302],[6,303],[6,304],[6,305],[6,306],[6,307],[6,308],[6,309],[6,310],[6,311],[6,312],[6,313],[6,314],[6,315],[6,316],[6,317],[6,318],[6,319],[6,320],[6,321],[6,322],[6,323],[6,324],[6,325],[6,326],[6,327],[6,328],[6,329],[6,330],[6,331],[6,332],[6,333],[6,334],[6,335],[6,336],[6,337],[6,338],[6,339],[6,340],[6,341],[6,342],[6,343],[6,344],[6,345],[6,346],[6,347],[6,348],[6,349],[6,350],[6,351],[6,352],[6,353],[6,354],[6,355],[6,356],[6,357],[6,358],[6,359],[6,360],[6,361],[6,362],[6,363],[6,364],[6,365],[6,366],[6,367],[6,368],[6,369],[6,370],[6,371],[6,372],[6,373],[6,374],[6,375],[6,376],[6,377],[6,378],[6,379],[6,380],[6,381],[6,382],[6,383],[6,384],[6,385],[6,386],[6,387],[6,388],[6,389],[6,390],[6,391],[6,392],[6,393],[6,394],[6,395],[6,396],[6,397],[6,398],[6,399],[6,400],[6,401],[6,402],[6,403],[6,404],[6,405],[6,406],[6,407],[6,408],[6,409],[6,410],[6,411],[6,412],[6,413],[6,414],[6,415],[6,416],[6,417],[6,418],[6,419],[6,420],[6,421],[6,422],[6,423],[6,424],[6,425],[6,426],[6,427],[6,428],[6,429],[6,430],[6,431],[6,432],[6,433],[6,434],[6,435],[6,436],[6,437],[6,438],[6,439],[6,440],[6,441],[6,442],[6,443],[6,444],[6,445],[6,446],[6,447],[6,448],[6,449],[6,450],[6,451],[6,452],[6,453],[6,454],[6,455],[6,456],[6,457],[6,458],[6,459],[6,460],[6,461],[6,462],[6,463],[6,464],[6,465],[6,466],[6,467],[6,468],[6,469],[6,470],[6,471],[6,472],[6,473],[6,474],[6,475],[6,476],[6,477],[6,478],[6,479],[6,480],[6,481],[6,482],[6,483],[6,484],[6,485],[6,486],[6,487],[6,488],[6,489],[6,490],[6,491],[6,492],[6,493],[6,494],[6,495],[6,496],[6,497],[6,498],[6,499],[6,500],[7,2],[7,3],[7,4],[7,5],[7,6],[7,7],[7,8],[7,9],[7,10],[7,11],[7,12],[7,13],[7,14],[7,15],[7,16],[7,17],[7,18],[7,19],[7,20],[7,21],[7,22],[7,23],[7,24],[7,25],[7,26],[7,27],[7,28],[7,29],[7,30],[7,31],[7,32],[7,33],[7,34],[7,35],[7,36],[7,37],[7,38],[7,39],[7,40],[7,41],[7,42],[7,43],[7,44],[7,45],[7,46],[7,47],[7,48],[7,49],[7,50],[7,51],[7,52],[7,53],[7,54],[7,55],[7,56],[7,57],[7,58],[7,59],[7,60],[7,61],[7,62],[7,63],[7,64],[7,65],[7,66],[7,67],[7,68],[7,69],[7,70],[7,71],[7,72],[7,73],[7,74],[7,75],[7,76],[7,77],[7,78],[7,79],[7,80],[7,81],[7,82],[7,83],[7,84],[7,85],[7,86],[7,87],[7,88],[7,89],[7,90],[7,91],[7,92],[7,93],[7,94],[7,95],[7,96],[7,97],[7,98],[7,99],[7,100],[7,101],[7,102],[7,103],[7,104],[7,105],[7,106],[7,107],[7,108],[7,109],[7,110],[7,111],[7,112],[7,113],[7,114],[7,115],[7,116],[7,117],[7,118],[7,119],[7,120],[7,121],[7,122],[7,123],[7,124],[7,125],[7,126],[7,127],[7,128],[7,129],[7,130],[7,131],[7,132],[7,133],[7,134],[7,135],[7,136],[7,137],[7,138],[7,139],[7,140],[7,141],[7,142],[7,143],[7,144],[7,145],[7,146],[7,147],[7,148],[7,149],[7,150],[7,151],[7,152],[7,153],[7,154],[7,155],[7,156],[7,157],[7,158],[7,159],[7,160],[7,161],[7,162],[7,163],[7,164],[7,165],[7,166],[7,167],[7,168],[7,169],[7,170],[7,171],[7,172],[7,173],[7,174],[7,175],[7,176],[7,177],[7,178],[7,179],[7,180],[7,181],[7,182],[7,183],[7,184],[7,185],[7,186],[7,187],[7,188],[7,189],[7,190],[7,191],[7,192],[7,193],[7,194],[7,195],[7,196],[7,197],[7,198],[7,199],[7,200],[7,201],[7,202],[7,203],[7,204],[7,205],[7,206],[7,207],[7,208],[7,209],[7,210],[7,211],[7,212],[7,213],[7,214],[7,215],[7,216],[7,217],[7,218],[7,219],[7,220],[7,221],[7,222],[7,223],[7,224],[7,225],[7,226],[7,227],[7,228],[7,229],[7,230],[7,231],[7,232],[7,233],[7,234],[7,235],[7,236],[7,237],[7,238],[7,239],[7,240],[7,241],[7,242],[7,243],[7,244],[7,245],[7,246],[7,247],[7,248],[7,249],[7,250],[7,251],[7,252],[7,253],[7,254],[7,255],[7,256],[7,257],[7,258],[7,259],[7,260],[7,261],[7,262],[7,263],[7,264],[7,265],[7,266],[7,267],[7,268],[7,269],[7,270],[7,271],[7,272],[7,273],[7,274],[7,275],[7,276],[7,277],[7,278],[7,279],[7,280],[7,281],[7,282],[7,283],[7,284],[7,285],[7,286],[7,287],[7,288],[7,289],[7,290],[7,291],[7,292],[7,293],[7,294],[7,295],[7,296],[7,297],[7,298],[7,299],[7,300],[7,301],[7,302],[7,303],[7,304],[7,305],[7,306],[7,307],[7,308],[7,309],[7,310],[7,311],[7,312],[7,313],[7,314],[7,315],[7,316],[7,317],[7,318],[7,319],[7,320],[7,321],[7,322],[7,323],[7,324],[7,325],[7,326],[7,327],[7,328],[7,329],[7,330],[7,331],[7,332],[7,333],[7,334],[7,335],[7,336],[7,337],[7,338],[7,339],[7,340],[7,341],[7,342],[7,343],[7,344],[7,345],[7,346],[7,347],[7,348],[7,349],[7,350],[7,351],[7,352],[7,353],[7,354],[7,355],[7,356],[7,357],[7,358],[7,359],[7,360],[7,361],[7,362],[7,363],[7,364],[7,365],[7,366],[7,367],[7,368],[7,369],[7,370],[7,371],[7,372],[7,373],[7,374],[7,375],[7,376],[7,377],[7,378],[7,379],[7,380],[7,381],[7,382],[7,383],[7,384],[7,385],[7,386],[7,387],[7,388],[7,389],[7,390],[7,391],[7,392],[7,393],[7,394],[7,395],[7,396],[7,397],[7,398],[7,399],[7,400],[7,401],[7,402],[7,403],[7,404],[7,405],[7,406],[7,407],[7,408],[7,409],[7,410],[7,411],[7,412],[7,413],[7,414],[7,415],[7,416],[7,417],[7,418],[7,419],[7,420],[7,421],[7,422],[7,423],[7,424],[7,425],[7,426],[7,427],[7,428],[7,429],[7,430],[7,431],[7,432],[7,433],[7,434],[7,435],[7,436],[7,437],[7,438],[7,439],[7,440],[7,441],[7,442],[7,443],[7,444],[7,445],[7,446],[7,447],[7,448],[7,449],[7,450],[7,451],[7,452],[7,453],[7,454],[7,455],[7,456],[7,457],[7,458],[7,459],[7,460],[7,461],[7,462],[7,463],[7,464],[7,465],[7,466],[7,467],[7,468],[7,469],[7,470],[7,471],[7,472],[7,473],[7,474],[7,475],[7,476],[7,477],[7,478],[7,479],[7,480],[7,481],[7,482],[7,483],[7,484],[7,485],[7,486],[7,487],[7,488],[7,489],[7,490],[7,491],[7,492],[7,493],[7,494],[7,495],[7,496],[7,497],[7,498],[7,499],[7,500],[11,8],[11,10],[11,10],[11,10],[11,10],[11,10],[11,10],[0,501],[0,502],[0,503],[1,501],[1,502],[1,503],[2,501],[2,502],[2,503],[3,501],[3,502],[3,503],[4,501],[4,502],[4,503],[5,501],[5,502],[5,503],[6,501],[6,502],[6,503],[7,501],[7,502],[7,503]],\"12,3\":[[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10],[0,11],[0,12],[0,13],[0,14],[0,15],[0,16],[0,17],[0,18],[0,19],[0,20],[0,21],[0,22],[0,23],[0,24],[0,25],[0,26],[0,27],[0,28],[0,29],[0,30],[0,31],[0,32],[0,33],[0,34],[0,35],[0,36],[0,37],[0,38],[0,39],[0,40],[0,41],[0,42],[0,43],[0,44],[0,45],[0,46],[0,47],[0,48],[0,49],[0,50],[0,51],[0,52],[0,53],[0,54],[0,55],[0,56],[0,57],[0,58],[0,59],[0,60],[0,61],[0,62],[0,63],[0,64],[0,65],[0,66],[0,67],[0,68],[0,69],[0,70],[0,71],[0,72],[0,73],[0,74],[0,75],[0,76],[0,77],[0,78],[0,79],[0,80],[0,81],[0,82],[0,83],[0,84],[0,85],[0,86],[0,87],[0,88],[0,89],[0,90],[0,91],[0,92],[0,93],[0,94],[0,95],[0,96],[0,97],[0,98],[0,99],[0,100],[0,101],[0,102],[0,103],[0,104],[0,105],[0,106],[0,107],[0,108],[0,109],[0,110],[0,111],[0,112],[0,113],[0,114],[0,115],[0,116],[0,117],[0,118],[0,119],[0,120],[0,121],[0,122],[0,123],[0,124],[0,125],[0,126],[0,127],[0,128],[0,129],[0,130],[0,131],[0,132],[0,133],[0,134],[0,135],[0,136],[0,137],[0,138],[0,139],[0,140],[0,141],[0,142],[0,143],[0,144],[0,145],[0,146],[0,147],[0,148],[0,149],[0,150],[0,151],[0,152],[0,153],[0,154],[0,155],[0,156],[0,157],[0,158],[0,159],[0,160],[0,161],[0,162],[0,163],[0,164],[0,165],[0,166],[0,167],[0,168],[0,169],[0,170],[0,171],[0,172],[0,173],[0,174],[0,175],[0,176],[0,177],[0,178],[0,179],[0,180],[0,181],[0,182],[0,183],[0,184],[0,185],[0,186],[0,187],[0,188],[0,189],[0,190],[0,191],[0,192],[0,193],[0,194],[0,195],[0,196],[0,197],[0,198],[0,199],[0,200],[0,201],[0,202],[0,203],[0,204],[0,205],[0,206],[0,207],[0,208],[0,209],[0,210],[0,211],[0,212],[0,213],[0,214],[0,215],[0,216],[0,217],[0,218],[0,219],[0,220],[0,221],[0,222],[0,223],[0,224],[0,225],[0,226],[0,227],[0,228],[0,229],[0,230],[0,231],[0,232],[0,233],[0,234],[0,235],[0,236],[0,237],[0,238],[0,239],[0,240],[0,241],[0,242],[0,243],[0,244],[0,245],[0,246],[0,247],[0,248],[0,249],[0,250],[0,251],[0,252],[0,253],[0,254],[0,255],[0,256],[0,257],[0,258],[0,259],[0,260],[0,261],[0,262],[0,263],[0,264],[0,265],[0,266],[0,267],[0,268],[0,269],[0,270],[0,271],[0,272],[0,273],[0,274],[0,275],[0,276],[0,277],[0,278],[0,279],[0,280],[0,281],[0,282],[0,283],[0,284],[0,285],[0,286],[0,287],[0,288],[0,289],[0,290],[0,291],[0,292],[0,293],[0,294],[0,295],[0,296],[0,297],[0,298],[0,299],[0,300],[0,301],[0,302],[0,303],[0,304],[0,305],[0,306],[0,307],[0,308],[0,309],[0,310],[0,311],[0,312],[0,313],[0,314],[0,315],[0,316],[0,317],[0,318],[0,319],[0,320],[0,321],[0,322],[0,323],[0,324],[0,325],[0,326],[0,327],[0,328],[0,329],[0,330],[0,331],[0,332],[0,333],[0,334],[0,335],[0,336],[0,337],[0,338],[0,339],[0,340],[0,341],[0,342],[0,343],[0,344],[0,345],[0,346],[0,347],[0,348],[0,349],[0,350],[0,351],[0,352],[0,353],[0,354],[0,355],[0,356],[0,357],[0,358],[0,359],[0,360],[0,361],[0,362],[0,363],[0,364],[0,365],[0,366],[0,367],[0,368],[0,369],[0,370],[0,371],[0,372],[0,373],[0,374],[0,375],[0,376],[0,377],[0,378],[0,379],[0,380],[0,381],[0,382],[0,383],[0,384],[0,385],[0,386],[0,387],[0,388],[0,389],[0,390],[0,391],[0,392],[0,393],[0,394],[0,395],[0,396],[0,397],[0,398],[0,399],[0,400],[0,401],[0,402],[0,403],[0,404],[0,405],[0,406],[0,407],[0,408],[0,409],[0,410],[0,411],[0,412],[0,413],[0,414],[0,415],[0,416],[0,417],[0,418],[0,419],[0,420],[0,421],[0,422],[0,423],[0,424],[0,425],[0,426],[0,427],[0,428],[0,429],[0,430],[0,431],[0,432],[0,433],[0,434],[0,435],[0,436],[0,437],[0,438],[0,439],[0,440],[0,441],[0,442],[0,443],[0,444],[0,445],[0,446],[0,447],[0,448],[0,449],[0,450],[0,451],[0,452],[0,453],[0,454],[0,455],[0,456],[0,457],[0,458],[0,459],[0,460],[0,461],[0,462],[0,463],[0,464],[0,465],[0,466],[0,467],[0,468],[0,469],[0,470],[0,471],[0,472],[0,473],[0,474],[0,475],[0,476],[0,477],[0,478],[0,479],[0,480],[0,481],[0,482],[0,483],[0,484],[0,485],[0,486],[0,487],[0,488],[0,489],[0,490],[0,491],[0,492],[0,493],[0,494],[0,495],[0,496],[0,497],[0,498],[0,499],[0,500],[1,2],[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],[1,9],[1,10],[1,11],[1,12],[1,13],[1,14],[1,15],[1,16],[1,17],[1,18],[1,19],[1,20],[1,21],[1,22],[1,23],[1,24],[1,25],[1,26],[1,27],[1,28],[1,29],[1,30],[1,31],[1,32],[1,33],[1,34],[1,35],[1,36],[1,37],[1,38],[1,39],[1,40],[1,41],[1,42],[1,43],[1,44],[1,45],[1,46],[1,47],[1,48],[1,49],[1,50],[1,51],[1,52],[1,53],[1,54],[1,55],[1,56],[1,57],[1,58],[1,59],[1,60],[1,61],[1,62],[1,63],[1,64],[1,65],[1,66],[1,67],[1,68],[1,69],[1,70],[1,71],[1,72],[1,73],[1,74],[1,75],[1,76],[1,77],[1,78],[1,79],[1,80],[1,81],[1,82],[1,83],[1,84],[1,85],[1,86],[1,87],[1,88],[1,89],[1,90],[1,91],[1,92],[1,93],[1,94],[1,95],[1,96],[1,97],[1,98],[1,99],[1,100],[1,101],[1,102],[1,103],[1,104],[1,105],[1,106],[1,107],[1,108],[1,109],[1,110],[1,111],[1,112],[1,113],[1,114],[1,115],[1,116],[1,117],[1,118],[1,119],[1,120],[1,121],[1,122],[1,123],[1,124],[1,125],[1,126],[1,127],[1,128],[1,129],[1,130],[1,131],[1,132],[1,133],[1,134],[1,135],[1,136],[1,137],[1,138],[1,139],[1,140],[1,141],[1,142],[1,143],[1,144],[1,145],[1,146],[1,147],[1,148],[1,149],[1,150],[1,151],[1,152],[1,153],[1,154],[1,155],[1,156],[1,157],[1,158],[1,159],[1,160],[1,161],[1,162],[1,163],[1,164],[1,165],[1,166],[1,167],[1,168],[1,169],[1,170],[1,171],[1,172],[1,173],[1,174],[1,175],[1,176],[1,177],[1,178],[1,179],[1,180],[1,181],[1,182],[1,183],[1,184],[1,185],[1,186],[1,187],[1,188],[1,189],[1,190],[1,191],[1,192],[1,193],[1,194],[1,195],[1,196],[1,197],[1,198],[1,199],[1,200],[1,201],[1,202],[1,203],[1,204],[1,205],[1,206],[1,207],[1,208],[1,209],[1,210],[1,211],[1,212],[1,213],[1,214],[1,215],[1,216],[1,217],[1,218],[1,219],[1,220],[1,221],[1,222],[1,223],[1,224],[1,225],[1,226],[1,227],[1,228],[1,229],[1,230],[1,231],[1,232],[1,233],[1,234],[1,235],[1,236],[1,237],[1,238],[1,239],[1,240],[1,241],[1,242],[1,243],[1,244],[1,245],[1,246],[1,247],[1,248],[1,249],[1,250],[1,251],[1,252],[1,253],[1,254],[1,255],[1,256],[1,257],[1,258],[1,259],[1,260],[1,261],[1,262],[1,263],[1,264],[1,265],[1,266],[1,267],[1,268],[1,269],[1,270],[1,271],[1,272],[1,273],[1,274],[1,275],[1,276],[1,277],[1,278],[1,279],[1,280],[1,281],[1,282],[1,283],[1,284],[1,285],[1,286],[1,287],[1,288],[1,289],[1,290],[1,291],[1,292],[1,293],[1,294],[1,295],[1,296],[1,297],[1,298],[1,299],[1,300],[1,301],[1,302],[1,303],[1,304],[1,305],[1,306],[1,307],[1,308],[1,309],[1,310],[1,311],[1,312],[1,313],[1,314],[1,315],[1,316],[1,317],[1,318],[1,319],[1,320],[1,321],[1,322],[1,323],[1,324],[1,325],[1,326],[1,327],[1,328],[1,329],[1,330],[1,331],[1,332],[1,333],[1,334],[1,335],[1,336],[1,337],[1,338],[1,339],[1,340],[1,341],[1,342],[1,343],[1,344],[1,345],[1,346],[1,347],[1,348],[1,349],[1,350],[1,351],[1,352],[1,353],[1,354],[1,355],[1,356],[1,357],[1,358],[1,359],[1,360],[1,361],[1,362],[1,363],[1,364],[1,365],[1,366],[1,367],[1,368],[1,369],[1,370],[1,371],[1,372],[1,373],[1,374],[1,375],[1,376],[1,377],[1,378],[1,379],[1,380],[1,381],[1,382],[1,383],[1,384],[1,385],[1,386],[1,387],[1,388],[1,389],[1,390],[1,391],[1,392],[1,393],[1,394],[1,395],[1,396],[1,397],[1,398],[1,399],[1,400],[1,401],[1,402],[1,403],[1,404],[1,405],[1,406],[1,407],[1,408],[1,409],[1,410],[1,411],[1,412],[1,413],[1,414],[1,415],[1,416],[1,417],[1,418],[1,419],[1,420],[1,421],[1,422],[1,423],[1,424],[1,425],[1,426],[1,427],[1,428],[1,429],[1,430],[1,431],[1,432],[1,433],[1,434],[1,435],[1,436],[1,437],[1,438],[1,439],[1,440],[1,441],[1,442],[1,443],[1,444],[1,445],[1,446],[1,447],[1,448],[1,449],[1,450],[1,451],[1,452],[1,453],[1,454],[1,455],[1,456],[1,457],[1,458],[1,459],[1,460],[1,461],[1,462],[1,463],[1,464],[1,465],[1,466],[1,467],[1,468],[1,469],[1,470],[1,471],[1,472],[1,473],[1,474],[1,475],[1,476],[1,477],[1,478],[1,479],[1,480],[1,481],[1,482],[1,483],[1,484],[1,485],[1,486],[1,487],[1,488],[1,489],[1,490],[1,491],[1,492],[1,493],[1,494],[1,495],[1,496],[1,497],[1,498],[1,499],[1,500],[2,2],[2,3],[2,4],[2,5],[2,6],[2,7],[2,8],[2,9],[2,10],[2,11],[2,12],[2,13],[2,14],[2,15],[2,16],[2,17],[2,18],[2,19],[2,20],[2,21],[2,22],[2,23],[2,24],[2,25],[2,26],[2,27],[2,28],[2,29],[2,30],[2,31],[2,32],[2,33],[2,34],[2,35],[2,36],[2,37],[2,38],[2,39],[2,40],[2,41],[2,42],[2,43],[2,44],[2,45],[2,46],[2,47],[2,48],[2,49],[2,50],[2,51],[2,52],[2,53],[2,54],[2,55],[2,56],[2,57],[2,58],[2,59],[2,60],[2,61],[2,62],[2,63],[2,64],[2,65],[2,66],[2,67],[2,68],[2,69],[2,70],[2,71],[2,72],[2,73],[2,74],[2,75],[2,76],[2,77],[2,78],[2,79],[2,80],[2,81],[2,82],[2,83],[2,84],[2,85],[2,86],[2,87],[2,88],[2,89],[2,90],[2,91],[2,92],[2,93],[2,94],[2,95],[2,96],[2,97],[2,98],[2,99],[2,100],[2,101],[2,102],[2,103],[2,104],[2,105],[2,106],[2,107],[2,108],[2,109],[2,110],[2,111],[2,112],[2,113],[2,114],[2,115],[2,116],[2,117],[2,118],[2,119],[2,120],[2,121],[2,122],[2,123],[2,124],[2,125],[2,126],[2,127],[2,128],[2,129],[2,130],[2,131],[2,132],[2,133],[2,134],[2,135],[2,136],[2,137],[2,138],[2,139],[2,140],[2,141],[2,142],[2,143],[2,144],[2,145],[2,146],[2,147],[2,148],[2,149],[2,150],[2,151],[2,152],[2,153],[2,154],[2,155],[2,156],[2,157],[2,158],[2,159],[2,160],[2,161],[2,162],[2,163],[2,164],[2,165],[2,166],[2,167],[2,168],[2,169],[2,170],[2,171],[2,172],[2,173],[2,174],[2,175],[2,176],[2,177],[2,178],[2,179],[2,180],[2,181],[2,182],[2,183],[2,184],[2,185],[2,186],[2,187],[2,188],[2,189],[2,190],[2,191],[2,192],[2,193],[2,194],[2,195],[2,196],[2,197],[2,198],[2,199],[2,200],[2,201],[2,202],[2,203],[2,204],[2,205],[2,206],[2,207],[2,208],[2,209],[2,210],[2,211],[2,212],[2,213],[2,214],[2,215],[2,216],[2,217],[2,218],[2,219],[2,220],[2,221],[2,222],[2,223],[2,224],[2,225],[2,226],[2,227],[2,228],[2,229],[2,230],[2,231],[2,232],[2,233],[2,234],[2,235],[2,236],[2,237],[2,238],[2,239],[2,240],[2,241],[2,242],[2,243],[2,244],[2,245],[2,246],[2,247],[2,248],[2,249],[2,250],[2,251],[2,252],[2,253],[2,254],[2,255],[2,256],[2,257],[2,258],[2,259],[2,260],[2,261],[2,262],[2,263],[2,264],[2,265],[2,266],[2,267],[2,268],[2,269],[2,270],[2,271],[2,272],[2,273],[2,274],[2,275],[2,276],[2,277],[2,278],[2,279],[2,280],[2,281],[2,282],[2,283],[2,284],[2,285],[2,286],[2,287],[2,288],[2,289],[2,290],[2,291],[2,292],[2,293],[2,294],[2,295],[2,296],[2,297],[2,298],[2,299],[2,300],[2,301],[2,302],[2,303],[2,304],[2,305],[2,306],[2,307],[2,308],[2,309],[2,310],[2,311],[2,312],[2,313],[2,314],[2,315],[2,316],[2,317],[2,318],[2,319],[2,320],[2,321],[2,322],[2,323],[2,324],[2,325],[2,326],[2,327],[2,328],[2,329],[2,330],[2,331],[2,332],[2,333],[2,334],[2,335],[2,336],[2,337],[2,338],[2,339],[2,340],[2,341],[2,342],[2,343],[2,344],[2,345],[2,346],[2,347],[2,348],[2,349],[2,350],[2,351],[2,352],[2,353],[2,354],[2,355],[2,356],[2,357],[2,358],[2,359],[2,360],[2,361],[2,362],[2,363],[2,364],[2,365],[2,366],[2,367],[2,368],[2,369],[2,370],[2,371],[2,372],[2,373],[2,374],[2,375],[2,376],[2,377],[2,378],[2,379],[2,380],[2,381],[2,382],[2,383],[2,384],[2,385],[2,386],[2,387],[2,388],[2,389],[2,390],[2,391],[2,392],[2,393],[2,394],[2,395],[2,396],[2,397],[2,398],[2,399],[2,400],[2,401],[2,402],[2,403],[2,404],[2,405],[2,406],[2,407],[2,408],[2,409],[2,410],[2,411],[2,412],[2,413],[2,414],[2,415],[2,416],[2,417],[2,418],[2,419],[2,420],[2,421],[2,422],[2,423],[2,424],[2,425],[2,426],[2,427],[2,428],[2,429],[2,430],[2,431],[2,432],[2,433],[2,434],[2,435],[2,436],[2,437],[2,438],[2,439],[2,440],[2,441],[2,442],[2,443],[2,444],[2,445],[2,446],[2,447],[2,448],[2,449],[2,450],[2,451],[2,452],[2,453],[2,454],[2,455],[2,456],[2,457],[2,458],[2,459],[2,460],[2,461],[2,462],[2,463],[2,464],[2,465],[2,466],[2,467],[2,468],[2,469],[2,470],[2,471],[2,472],[2,473],[2,474],[2,475],[2,476],[2,477],[2,478],[2,479],[2,480],[2,481],[2,482],[2,483],[2,484],[2,485],[2,486],[2,487],[2,488],[2,489],[2,490],[2,491],[2,492],[2,493],[2,494],[2,495],[2,496],[2,497],[2,498],[2,499],[2,500],[3,2],[3,3],[3,4],[3,5],[3,6],[3,7],[3,8],[3,9],[3,10],[3,11],[3,12],[3,13],[3,14],[3,15],[3,16],[3,17],[3,18],[3,19],[3,20],[3,21],[3,22],[3,23],[3,24],[3,25],[3,26],[3,27],[3,28],[3,29],[3,30],[3,31],[3,32],[3,33],[3,34],[3,35],[3,36],[3,37],[3,38],[3,39],[3,40],[3,41],[3,42],[3,43],[3,44],[3,45],[3,46],[3,47],[3,48],[3,49],[3,50],[3,51],[3,52],[3,53],[3,54],[3,55],[3,56],[3,57],[3,58],[3,59],[3,60],[3,61],[3,62],[3,63],[3,64],[3,65],[3,66],[3,67],[3,68],[3,69],[3,70],[3,71],[3,72],[3,73],[3,74],[3,75],[3,76],[3,77],[3,78],[3,79],[3,80],[3,81],[3,82],[3,83],[3,84],[3,85],[3,86],[3,87],[3,88],[3,89],[3,90],[3,91],[3,92],[3,93],[3,94],[3,95],[3,96],[3,97],[3,98],[3,99],[3,100],[3,101],[3,102],[3,103],[3,104],[3,105],[3,106],[3,107],[3,108],[3,109],[3,110],[3,111],[3,112],[3,113],[3,114],[3,115],[3,116],[3,117],[3,118],[3,119],[3,120],[3,121],[3,122],[3,123],[3,124],[3,125],[3,126],[3,127],[3,128],[3,129],[3,130],[3,131],[3,132],[3,133],[3,134],[3,135],[3,136],[3,137],[3,138],[3,139],[3,140],[3,141],[3,142],[3,143],[3,144],[3,145],[3,146],[3,147],[3,148],[3,149],[3,150],[3,151],[3,152],[3,153],[3,154],[3,155],[3,156],[3,157],[3,158],[3,159],[3,160],[3,161],[3,162],[3,163],[3,164],[3,165],[3,166],[3,167],[3,168],[3,169],[3,170],[3,171],[3,172],[3,173],[3,174],[3,175],[3,176],[3,177],[3,178],[3,179],[3,180],[3,181],[3,182],[3,183],[3,184],[3,185],[3,186],[3,187],[3,188],[3,189],[3,190],[3,191],[3,192],[3,193],[3,194],[3,195],[3,196],[3,197],[3,198],[3,199],[3,200],[3,201],[3,202],[3,203],[3,204],[3,205],[3,206],[3,207],[3,208],[3,209],[3,210],[3,211],[3,212],[3,213],[3,214],[3,215],[3,216],[3,217],[3,218],[3,219],[3,220],[3,221],[3,222],[3,223],[3,224],[3,225],[3,226],[3,227],[3,228],[3,229],[3,230],[3,231],[3,232],[3,233],[3,234],[3,235],[3,236],[3,237],[3,238],[3,239],[3,240],[3,241],[3,242],[3,243],[3,244],[3,245],[3,246],[3,247],[3,248],[3,249],[3,250],[3,251],[3,252],[3,253],[3,254],[3,255],[3,256],[3,257],[3,258],[3,259],[3,260],[3,261],[3,262],[3,263],[3,264],[3,265],[3,266],[3,267],[3,268],[3,269],[3,270],[3,271],[3,272],[3,273],[3,274],[3,275],[3,276],[3,277],[3,278],[3,279],[3,280],[3,281],[3,282],[3,283],[3,284],[3,285],[3,286],[3,287],[3,288],[3,289],[3,290],[3,291],[3,292],[3,293],[3,294],[3,295],[3,296],[3,297],[3,298],[3,299],[3,300],[3,301],[3,302],[3,303],[3,304],[3,305],[3,306],[3,307],[3,308],[3,309],[3,310],[3,311],[3,312],[3,313],[3,314],[3,315],[3,316],[3,317],[3,318],[3,319],[3,320],[3,321],[3,322],[3,323],[3,324],[3,325],[3,326],[3,327],[3,328],[3,329],[3,330],[3,331],[3,332],[3,333],[3,334],[3,335],[3,336],[3,337],[3,338],[3,339],[3,340],[3,341],[3,342],[3,343],[3,344],[3,345],[3,346],[3,347],[3,348],[3,349],[3,350],[3,351],[3,352],[3,353],[3,354],[3,355],[3,356],[3,357],[3,358],[3,359],[3,360],[3,361],[3,362],[3,363],[3,364],[3,365],[3,366],[3,367],[3,368],[3,369],[3,370],[3,371],[3,372],[3,373],[3,374],[3,375],[3,376],[3,377],[3,378],[3,379],[3,380],[3,381],[3,382],[3,383],[3,384],[3,385],[3,386],[3,387],[3,388],[3,389],[3,390],[3,391],[3,392],[3,393],[3,394],[3,395],[3,396],[3,397],[3,398],[3,399],[3,400],[3,401],[3,402],[3,403],[3,404],[3,405],[3,406],[3,407],[3,408],[3,409],[3,410],[3,411],[3,412],[3,413],[3,414],[3,415],[3,416],[3,417],[3,418],[3,419],[3,420],[3,421],[3,422],[3,423],[3,424],[3,425],[3,426],[3,427],[3,428],[3,429],[3,430],[3,431],[3,432],[3,433],[3,434],[3,435],[3,436],[3,437],[3,438],[3,439],[3,440],[3,441],[3,442],[3,443],[3,444],[3,445],[3,446],[3,447],[3,448],[3,449],[3,450],[3,451],[3,452],[3,453],[3,454],[3,455],[3,456],[3,457],[3,458],[3,459],[3,460],[3,461],[3,462],[3,463],[3,464],[3,465],[3,466],[3,467],[3,468],[3,469],[3,470],[3,471],[3,472],[3,473],[3,474],[3,475],[3,476],[3,477],[3,478],[3,479],[3,480],[3,481],[3,482],[3,483],[3,484],[3,485],[3,486],[3,487],[3,488],[3,489],[3,490],[3,491],[3,492],[3,493],[3,494],[3,495],[3,496],[3,497],[3,498],[3,499],[3,500],[4,2],[4,3],[4,4],[4,5],[4,6],[4,7],[4,8],[4,9],[4,10],[4,11],[4,12],[4,13],[4,14],[4,15],[4,16],[4,17],[4,18],[4,19],[4,20],[4,21],[4,22],[4,23],[4,24],[4,25],[4,26],[4,27],[4,28],[4,29],[4,30],[4,31],[4,32],[4,33],[4,34],[4,35],[4,36],[4,37],[4,38],[4,39],[4,40],[4,41],[4,42],[4,43],[4,44],[4,45],[4,46],[4,47],[4,48],[4,49],[4,50],[4,51],[4,52],[4,53],[4,54],[4,55],[4,56],[4,57],[4,58],[4,59],[4,60],[4,61],[4,62],[4,63],[4,64],[4,65],[4,66],[4,67],[4,68],[4,69],[4,70],[4,71],[4,72],[4,73],[4,74],[4,75],[4,76],[4,77],[4,78],[4,79],[4,80],[4,81],[4,82],[4,83],[4,84],[4,85],[4,86],[4,87],[4,88],[4,89],[4,90],[4,91],[4,92],[4,93],[4,94],[4,95],[4,96],[4,97],[4,98],[4,99],[4,100],[4,101],[4,102],[4,103],[4,104],[4,105],[4,106],[4,107],[4,108],[4,109],[4,110],[4,111],[4,112],[4,113],[4,114],[4,115],[4,116],[4,117],[4,118],[4,119],[4,120],[4,121],[4,122],[4,123],[4,124],[4,125],[4,126],[4,127],[4,128],[4,129],[4,130],[4,131],[4,132],[4,133],[4,134],[4,135],[4,136],[4,137],[4,138],[4,139],[4,140],[4,141],[4,142],[4,143],[4,144],[4,145],[4,146],[4,147],[4,148],[4,149],[4,150],[4,151],[4,152],[4,153],[4,154],[4,155],[4,156],[4,157],[4,158],[4,159],[4,160],[4,161],[4,162],[4,163],[4,164],[4,165],[4,166],[4,167],[4,168],[4,169],[4,170],[4,171],[4,172],[4,173],[4,174],[4,175],[4,176],[4,177],[4,178],[4,179],[4,180],[4,181],[4,182],[4,183],[4,184],[4,185],[4,186],[4,187],[4,188],[4,189],[4,190],[4,191],[4,192],[4,193],[4,194],[4,195],[4,196],[4,197],[4,198],[4,199],[4,200],[4,201],[4,202],[4,203],[4,204],[4,205],[4,206],[4,207],[4,208],[4,209],[4,210],[4,211],[4,212],[4,213],[4,214],[4,215],[4,216],[4,217],[4,218],[4,219],[4,220],[4,221],[4,222],[4,223],[4,224],[4,225],[4,226],[4,227],[4,228],[4,229],[4,230],[4,231],[4,232],[4,233],[4,234],[4,235],[4,236],[4,237],[4,238],[4,239],[4,240],[4,241],[4,242],[4,243],[4,244],[4,245],[4,246],[4,247],[4,248],[4,249],[4,250],[4,251],[4,252],[4,253],[4,254],[4,255],[4,256],[4,257],[4,258],[4,259],[4,260],[4,261],[4,262],[4,263],[4,264],[4,265],[4,266],[4,267],[4,268],[4,269],[4,270],[4,271],[4,272],[4,273],[4,274],[4,275],[4,276],[4,277],[4,278],[4,279],[4,280],[4,281],[4,282],[4,283],[4,284],[4,285],[4,286],[4,287],[4,288],[4,289],[4,290],[4,291],[4,292],[4,293],[4,294],[4,295],[4,296],[4,297],[4,298],[4,299],[4,300],[4,301],[4,302],[4,303],[4,304],[4,305],[4,306],[4,307],[4,308],[4,309],[4,310],[4,311],[4,312],[4,313],[4,314],[4,315],[4,316],[4,317],[4,318],[4,319],[4,320],[4,321],[4,322],[4,323],[4,324],[4,325],[4,326],[4,327],[4,328],[4,329],[4,330],[4,331],[4,332],[4,333],[4,334],[4,335],[4,336],[4,337],[4,338],[4,339],[4,340],[4,341],[4,342],[4,343],[4,344],[4,345],[4,346],[4,347],[4,348],[4,349],[4,350],[4,351],[4,352],[4,353],[4,354],[4,355],[4,356],[4,357],[4,358],[4,359],[4,360],[4,361],[4,362],[4,363],[4,364],[4,365],[4,366],[4,367],[4,368],[4,369],[4,370],[4,371],[4,372],[4,373],[4,374],[4,375],[4,376],[4,377],[4,378],[4,379],[4,380],[4,381],[4,382],[4,383],[4,384],[4,385],[4,386],[4,387],[4,388],[4,389],[4,390],[4,391],[4,392],[4,393],[4,394],[4,395],[4,396],[4,397],[4,398],[4,399],[4,400],[4,401],[4,402],[4,403],[4,404],[4,405],[4,406],[4,407],[4,408],[4,409],[4,410],[4,411],[4,412],[4,413],[4,414],[4,415],[4,416],[4,417],[4,418],[4,419],[4,420],[4,421],[4,422],[4,423],[4,424],[4,425],[4,426],[4,427],[4,428],[4,429],[4,430],[4,431],[4,432],[4,433],[4,434],[4,435],[4,436],[4,437],[4,438],[4,439],[4,440],[4,441],[4,442],[4,443],[4,444],[4,445],[4,446],[4,447],[4,448],[4,449],[4,450],[4,451],[4,452],[4,453],[4,454],[4,455],[4,456],[4,457],[4,458],[4,459],[4,460],[4,461],[4,462],[4,463],[4,464],[4,465],[4,466],[4,467],[4,468],[4,469],[4,470],[4,471],[4,472],[4,473],[4,474],[4,475],[4,476],[4,477],[4,478],[4,479],[4,480],[4,481],[4,482],[4,483],[4,484],[4,485],[4,486],[4,487],[4,488],[4,489],[4,490],[4,491],[4,492],[4,493],[4,494],[4,495],[4,496],[4,497],[4,498],[4,499],[4,500],[5,2],[5,3],[5,4],[5,5],[5,6],[5,7],[5,8],[5,9],[5,10],[5,11],[5,12],[5,13],[5,14],[5,15],[5,16],[5,17],[5,18],[5,19],[5,20],[5,21],[5,22],[5,23],[5,24],[5,25],[5,26],[5,27],[5,28],[5,29],[5,30],[5,31],[5,32],[5,33],[5,34],[5,35],[5,36],[5,37],[5,38],[5,39],[5,40],[5,41],[5,42],[5,43],[5,44],[5,45],[5,46],[5,47],[5,48],[5,49],[5,50],[5,51],[5,52],[5,53],[5,54],[5,55],[5,56],[5,57],[5,58],[5,59],[5,60],[5,61],[5,62],[5,63],[5,64],[5,65],[5,66],[5,67],[5,68],[5,69],[5,70],[5,71],[5,72],[5,73],[5,74],[5,75],[5,76],[5,77],[5,78],[5,79],[5,80],[5,81],[5,82],[5,83],[5,84],[5,85],[5,86],[5,87],[5,88],[5,89],[5,90],[5,91],[5,92],[5,93],[5,94],[5,95],[5,96],[5,97],[5,98],[5,99],[5,100],[5,101],[5,102],[5,103],[5,104],[5,105],[5,106],[5,107],[5,108],[5,109],[5,110],[5,111],[5,112],[5,113],[5,114],[5,115],[5,116],[5,117],[5,118],[5,119],[5,120],[5,121],[5,122],[5,123],[5,124],[5,125],[5,126],[5,127],[5,128],[5,129],[5,130],[5,131],[5,132],[5,133],[5,134],[5,135],[5,136],[5,137],[5,138],[5,139],[5,140],[5,141],[5,142],[5,143],[5,144],[5,145],[5,146],[5,147],[5,148],[5,149],[5,150],[5,151],[5,152],[5,153],[5,154],[5,155],[5,156],[5,157],[5,158],[5,159],[5,160],[5,161],[5,162],[5,163],[5,164],[5,165],[5,166],[5,167],[5,168],[5,169],[5,170],[5,171],[5,172],[5,173],[5,174],[5,175],[5,176],[5,177],[5,178],[5,179],[5,180],[5,181],[5,182],[5,183],[5,184],[5,185],[5,186],[5,187],[5,188],[5,189],[5,190],[5,191],[5,192],[5,193],[5,194],[5,195],[5,196],[5,197],[5,198],[5,199],[5,200],[5,201],[5,202],[5,203],[5,204],[5,205],[5,206],[5,207],[5,208],[5,209],[5,210],[5,211],[5,212],[5,213],[5,214],[5,215],[5,216],[5,217],[5,218],[5,219],[5,220],[5,221],[5,222],[5,223],[5,224],[5,225],[5,226],[5,227],[5,228],[5,229],[5,230],[5,231],[5,232],[5,233],[5,234],[5,235],[5,236],[5,237],[5,238],[5,239],[5,240],[5,241],[5,242],[5,243],[5,244],[5,245],[5,246],[5,247],[5,248],[5,249],[5,250],[5,251],[5,252],[5,253],[5,254],[5,255],[5,256],[5,257],[5,258],[5,259],[5,260],[5,261],[5,262],[5,263],[5,264],[5,265],[5,266],[5,267],[5,268],[5,269],[5,270],[5,271],[5,272],[5,273],[5,274],[5,275],[5,276],[5,277],[5,278],[5,279],[5,280],[5,281],[5,282],[5,283],[5,284],[5,285],[5,286],[5,287],[5,288],[5,289],[5,290],[5,291],[5,292],[5,293],[5,294],[5,295],[5,296],[5,297],[5,298],[5,299],[5,300],[5,301],[5,302],[5,303],[5,304],[5,305],[5,306],[5,307],[5,308],[5,309],[5,310],[5,311],[5,312],[5,313],[5,314],[5,315],[5,316],[5,317],[5,318],[5,319],[5,320],[5,321],[5,322],[5,323],[5,324],[5,325],[5,326],[5,327],[5,328],[5,329],[5,330],[5,331],[5,332],[5,333],[5,334],[5,335],[5,336],[5,337],[5,338],[5,339],[5,340],[5,341],[5,342],[5,343],[5,344],[5,345],[5,346],[5,347],[5,348],[5,349],[5,350],[5,351],[5,352],[5,353],[5,354],[5,355],[5,356],[5,357],[5,358],[5,359],[5,360],[5,361],[5,362],[5,363],[5,364],[5,365],[5,366],[5,367],[5,368],[5,369],[5,370],[5,371],[5,372],[5,373],[5,374],[5,375],[5,376],[5,377],[5,378],[5,379],[5,380],[5,381],[5,382],[5,383],[5,384],[5,385],[5,386],[5,387],[5,388],[5,389],[5,390],[5,391],[5,392],[5,393],[5,394],[5,395],[5,396],[5,397],[5,398],[5,399],[5,400],[5,401],[5,402],[5,403],[5,404],[5,405],[5,406],[5,407],[5,408],[5,409],[5,410],[5,411],[5,412],[5,413],[5,414],[5,415],[5,416],[5,417],[5,418],[5,419],[5,420],[5,421],[5,422],[5,423],[5,424],[5,425],[5,426],[5,427],[5,428],[5,429],[5,430],[5,431],[5,432],[5,433],[5,434],[5,435],[5,436],[5,437],[5,438],[5,439],[5,440],[5,441],[5,442],[5,443],[5,444],[5,445],[5,446],[5,447],[5,448],[5,449],[5,450],[5,451],[5,452],[5,453],[5,454],[5,455],[5,456],[5,457],[5,458],[5,459],[5,460],[5,461],[5,462],[5,463],[5,464],[5,465],[5,466],[5,467],[5,468],[5,469],[5,470],[5,471],[5,472],[5,473],[5,474],[5,475],[5,476],[5,477],[5,478],[5,479],[5,480],[5,481],[5,482],[5,483],[5,484],[5,485],[5,486],[5,487],[5,488],[5,489],[5,490],[5,491],[5,492],[5,493],[5,494],[5,495],[5,496],[5,497],[5,498],[5,499],[5,500],[6,2],[6,3],[6,4],[6,5],[6,6],[6,7],[6,8],[6,9],[6,10],[6,11],[6,12],[6,13],[6,14],[6,15],[6,16],[6,17],[6,18],[6,19],[6,20],[6,21],[6,22],[6,23],[6,24],[6,25],[6,26],[6,27],[6,28],[6,29],[6,30],[6,31],[6,32],[6,33],[6,34],[6,35],[6,36],[6,37],[6,38],[6,39],[6,40],[6,41],[6,42],[6,43],[6,44],[6,45],[6,46],[6,47],[6,48],[6,49],[6,50],[6,51],[6,52],[6,53],[6,54],[6,55],[6,56],[6,57],[6,58],[6,59],[6,60],[6,61],[6,62],[6,63],[6,64],[6,65],[6,66],[6,67],[6,68],[6,69],[6,70],[6,71],[6,72],[6,73],[6,74],[6,75],[6,76],[6,77],[6,78],[6,79],[6,80],[6,81],[6,82],[6,83],[6,84],[6,85],[6,86],[6,87],[6,88],[6,89],[6,90],[6,91],[6,92],[6,93],[6,94],[6,95],[6,96],[6,97],[6,98],[6,99],[6,100],[6,101],[6,102],[6,103],[6,104],[6,105],[6,106],[6,107],[6,108],[6,109],[6,110],[6,111],[6,112],[6,113],[6,114],[6,115],[6,116],[6,117],[6,118],[6,119],[6,120],[6,121],[6,122],[6,123],[6,124],[6,125],[6,126],[6,127],[6,128],[6,129],[6,130],[6,131],[6,132],[6,133],[6,134],[6,135],[6,136],[6,137],[6,138],[6,139],[6,140],[6,141],[6,142],[6,143],[6,144],[6,145],[6,146],[6,147],[6,148],[6,149],[6,150],[6,151],[6,152],[6,153],[6,154],[6,155],[6,156],[6,157],[6,158],[6,159],[6,160],[6,161],[6,162],[6,163],[6,164],[6,165],[6,166],[6,167],[6,168],[6,169],[6,170],[6,171],[6,172],[6,173],[6,174],[6,175],[6,176],[6,177],[6,178],[6,179],[6,180],[6,181],[6,182],[6,183],[6,184],[6,185],[6,186],[6,187],[6,188],[6,189],[6,190],[6,191],[6,192],[6,193],[6,194],[6,195],[6,196],[6,197],[6,198],[6,199],[6,200],[6,201],[6,202],[6,203],[6,204],[6,205],[6,206],[6,207],[6,208],[6,209],[6,210],[6,211],[6,212],[6,213],[6,214],[6,215],[6,216],[6,217],[6,218],[6,219],[6,220],[6,221],[6,222],[6,223],[6,224],[6,225],[6,226],[6,227],[6,228],[6,229],[6,230],[6,231],[6,232],[6,233],[6,234],[6,235],[6,236],[6,237],[6,238],[6,239],[6,240],[6,241],[6,242],[6,243],[6,244],[6,245],[6,246],[6,247],[6,248],[6,249],[6,250],[6,251],[6,252],[6,253],[6,254],[6,255],[6,256],[6,257],[6,258],[6,259],[6,260],[6,261],[6,262],[6,263],[6,264],[6,265],[6,266],[6,267],[6,268],[6,269],[6,270],[6,271],[6,272],[6,273],[6,274],[6,275],[6,276],[6,277],[6,278],[6,279],[6,280],[6,281],[6,282],[6,283],[6,284],[6,285],[6,286],[6,287],[6,288],[6,289],[6,290],[6,291],[6,292],[6,293],[6,294],[6,295],[6,296],[6,297],[6,298],[6,299],[6,300],[6,301],[6,302],[6,303],[6,304],[6,305],[6,306],[6,307],[6,308],[6,309],[6,310],[6,311],[6,312],[6,313],[6,314],[6,315],[6,316],[6,317],[6,318],[6,319],[6,320],[6,321],[6,322],[6,323],[6,324],[6,325],[6,326],[6,327],[6,328],[6,329],[6,330],[6,331],[6,332],[6,333],[6,334],[6,335],[6,336],[6,337],[6,338],[6,339],[6,340],[6,341],[6,342],[6,343],[6,344],[6,345],[6,346],[6,347],[6,348],[6,349],[6,350],[6,351],[6,352],[6,353],[6,354],[6,355],[6,356],[6,357],[6,358],[6,359],[6,360],[6,361],[6,362],[6,363],[6,364],[6,365],[6,366],[6,367],[6,368],[6,369],[6,370],[6,371],[6,372],[6,373],[6,374],[6,375],[6,376],[6,377],[6,378],[6,379],[6,380],[6,381],[6,382],[6,383],[6,384],[6,385],[6,386],[6,387],[6,388],[6,389],[6,390],[6,391],[6,392],[6,393],[6,394],[6,395],[6,396],[6,397],[6,398],[6,399],[6,400],[6,401],[6,402],[6,403],[6,404],[6,405],[6,406],[6,407],[6,408],[6,409],[6,410],[6,411],[6,412],[6,413],[6,414],[6,415],[6,416],[6,417],[6,418],[6,419],[6,420],[6,421],[6,422],[6,423],[6,424],[6,425],[6,426],[6,427],[6,428],[6,429],[6,430],[6,431],[6,432],[6,433],[6,434],[6,435],[6,436],[6,437],[6,438],[6,439],[6,440],[6,441],[6,442],[6,443],[6,444],[6,445],[6,446],[6,447],[6,448],[6,449],[6,450],[6,451],[6,452],[6,453],[6,454],[6,455],[6,456],[6,457],[6,458],[6,459],[6,460],[6,461],[6,462],[6,463],[6,464],[6,465],[6,466],[6,467],[6,468],[6,469],[6,470],[6,471],[6,472],[6,473],[6,474],[6,475],[6,476],[6,477],[6,478],[6,479],[6,480],[6,481],[6,482],[6,483],[6,484],[6,485],[6,486],[6,487],[6,488],[6,489],[6,490],[6,491],[6,492],[6,493],[6,494],[6,495],[6,496],[6,497],[6,498],[6,499],[6,500],[7,2],[7,3],[7,4],[7,5],[7,6],[7,7],[7,8],[7,9],[7,10],[7,11],[7,12],[7,13],[7,14],[7,15],[7,16],[7,17],[7,18],[7,19],[7,20],[7,21],[7,22],[7,23],[7,24],[7,25],[7,26],[7,27],[7,28],[7,29],[7,30],[7,31],[7,32],[7,33],[7,34],[7,35],[7,36],[7,37],[7,38],[7,39],[7,40],[7,41],[7,42],[7,43],[7,44],[7,45],[7,46],[7,47],[7,48],[7,49],[7,50],[7,51],[7,52],[7,53],[7,54],[7,55],[7,56],[7,57],[7,58],[7,59],[7,60],[7,61],[7,62],[7,63],[7,64],[7,65],[7,66],[7,67],[7,68],[7,69],[7,70],[7,71],[7,72],[7,73],[7,74],[7,75],[7,76],[7,77],[7,78],[7,79],[7,80],[7,81],[7,82],[7,83],[7,84],[7,85],[7,86],[7,87],[7,88],[7,89],[7,90],[7,91],[7,92],[7,93],[7,94],[7,95],[7,96],[7,97],[7,98],[7,99],[7,100],[7,101],[7,102],[7,103],[7,104],[7,105],[7,106],[7,107],[7,108],[7,109],[7,110],[7,111],[7,112],[7,113],[7,114],[7,115],[7,116],[7,117],[7,118],[7,119],[7,120],[7,121],[7,122],[7,123],[7,124],[7,125],[7,126],[7,127],[7,128],[7,129],[7,130],[7,131],[7,132],[7,133],[7,134],[7,135],[7,136],[7,137],[7,138],[7,139],[7,140],[7,141],[7,142],[7,143],[7,144],[7,145],[7,146],[7,147],[7,148],[7,149],[7,150],[7,151],[7,152],[7,153],[7,154],[7,155],[7,156],[7,157],[7,158],[7,159],[7,160],[7,161],[7,162],[7,163],[7,164],[7,165],[7,166],[7,167],[7,168],[7,169],[7,170],[7,171],[7,172],[7,173],[7,174],[7,175],[7,176],[7,177],[7,178],[7,179],[7,180],[7,181],[7,182],[7,183],[7,184],[7,185],[7,186],[7,187],[7,188],[7,189],[7,190],[7,191],[7,192],[7,193],[7,194],[7,195],[7,196],[7,197],[7,198],[7,199],[7,200],[7,201],[7,202],[7,203],[7,204],[7,205],[7,206],[7,207],[7,208],[7,209],[7,210],[7,211],[7,212],[7,213],[7,214],[7,215],[7,216],[7,217],[7,218],[7,219],[7,220],[7,221],[7,222],[7,223],[7,224],[7,225],[7,226],[7,227],[7,228],[7,229],[7,230],[7,231],[7,232],[7,233],[7,234],[7,235],[7,236],[7,237],[7,238],[7,239],[7,240],[7,241],[7,242],[7,243],[7,244],[7,245],[7,246],[7,247],[7,248],[7,249],[7,250],[7,251],[7,252],[7,253],[7,254],[7,255],[7,256],[7,257],[7,258],[7,259],[7,260],[7,261],[7,262],[7,263],[7,264],[7,265],[7,266],[7,267],[7,268],[7,269],[7,270],[7,271],[7,272],[7,273],[7,274],[7,275],[7,276],[7,277],[7,278],[7,279],[7,280],[7,281],[7,282],[7,283],[7,284],[7,285],[7,286],[7,287],[7,288],[7,289],[7,290],[7,291],[7,292],[7,293],[7,294],[7,295],[7,296],[7,297],[7,298],[7,299],[7,300],[7,301],[7,302],[7,303],[7,304],[7,305],[7,306],[7,307],[7,308],[7,309],[7,310],[7,311],[7,312],[7,313],[7,314],[7,315],[7,316],[7,317],[7,318],[7,319],[7,320],[7,321],[7,322],[7,323],[7,324],[7,325],[7,326],[7,327],[7,328],[7,329],[7,330],[7,331],[7,332],[7,333],[7,334],[7,335],[7,336],[7,337],[7,338],[7,339],[7,340],[7,341],[7,342],[7,343],[7,344],[7,345],[7,346],[7,347],[7,348],[7,349],[7,350],[7,351],[7,352],[7,353],[7,354],[7,355],[7,356],[7,357],[7,358],[7,359],[7,360],[7,361],[7,362],[7,363],[7,364],[7,365],[7,366],[7,367],[7,368],[7,369],[7,370],[7,371],[7,372],[7,373],[7,374],[7,375],[7,376],[7,377],[7,378],[7,379],[7,380],[7,381],[7,382],[7,383],[7,384],[7,385],[7,386],[7,387],[7,388],[7,389],[7,390],[7,391],[7,392],[7,393],[7,394],[7,395],[7,396],[7,397],[7,398],[7,399],[7,400],[7,401],[7,402],[7,403],[7,404],[7,405],[7,406],[7,407],[7,408],[7,409],[7,410],[7,411],[7,412],[7,413],[7,414],[7,415],[7,416],[7,417],[7,418],[7,419],[7,420],[7,421],[7,422],[7,423],[7,424],[7,425],[7,426],[7,427],[7,428],[7,429],[7,430],[7,431],[7,432],[7,433],[7,434],[7,435],[7,436],[7,437],[7,438],[7,439],[7,440],[7,441],[7,442],[7,443],[7,444],[7,445],[7,446],[7,447],[7,448],[7,449],[7,450],[7,451],[7,452],[7,453],[7,454],[7,455],[7,456],[7,457],[7,458],[7,459],[7,460],[7,461],[7,462],[7,463],[7,464],[7,465],[7,466],[7,467],[7,468],[7,469],[7,470],[7,471],[7,472],[7,473],[7,474],[7,475],[7,476],[7,477],[7,478],[7,479],[7,480],[7,481],[7,482],[7,483],[7,484],[7,485],[7,486],[7,487],[7,488],[7,489],[7,490],[7,491],[7,492],[7,493],[7,494],[7,495],[7,496],[7,497],[7,498],[7,499],[7,500],[11,3],[11,3],[11,3],[11,3],[0,501],[0,502],[0,503],[1,501],[1,502],[1,503],[2,501],[2,502],[2,503],[3,501],[3,502],[3,503],[4,501],[4,502],[4,503],[5,501],[5,502],[5,503],[6,501],[6,502],[6,503],[7,501],[7,502],[7,503]],\"12,4\":[[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10],[0,11],[0,12],[0,13],[0,14],[0,15],[0,16],[0,17],[0,18],[0,19],[0,20],[0,21],[0,22],[0,23],[0,24],[0,25],[0,26],[0,27],[0,28],[0,29],[0,30],[0,31],[0,32],[0,33],[0,34],[0,35],[0,36],[0,37],[0,38],[0,39],[0,40],[0,41],[0,42],[0,43],[0,44],[0,45],[0,46],[0,47],[0,48],[0,49],[0,50],[0,51],[0,52],[0,53],[0,54],[0,55],[0,56],[0,57],[0,58],[0,59],[0,60],[0,61],[0,62],[0,63],[0,64],[0,65],[0,66],[0,67],[0,68],[0,69],[0,70],[0,71],[0,72],[0,73],[0,74],[0,75],[0,76],[0,77],[0,78],[0,79],[0,80],[0,81],[0,82],[0,83],[0,84],[0,85],[0,86],[0,87],[0,88],[0,89],[0,90],[0,91],[0,92],[0,93],[0,94],[0,95],[0,96],[0,97],[0,98],[0,99],[0,100],[0,101],[0,102],[0,103],[0,104],[0,105],[0,106],[0,107],[0,108],[0,109],[0,110],[0,111],[0,112],[0,113],[0,114],[0,115],[0,116],[0,117],[0,118],[0,119],[0,120],[0,121],[0,122],[0,123],[0,124],[0,125],[0,126],[0,127],[0,128],[0,129],[0,130],[0,131],[0,132],[0,133],[0,134],[0,135],[0,136],[0,137],[0,138],[0,139],[0,140],[0,141],[0,142],[0,143],[0,144],[0,145],[0,146],[0,147],[0,148],[0,149],[0,150],[0,151],[0,152],[0,153],[0,154],[0,155],[0,156],[0,157],[0,158],[0,159],[0,160],[0,161],[0,162],[0,163],[0,164],[0,165],[0,166],[0,167],[0,168],[0,169],[0,170],[0,171],[0,172],[0,173],[0,174],[0,175],[0,176],[0,177],[0,178],[0,179],[0,180],[0,181],[0,182],[0,183],[0,184],[0,185],[0,186],[0,187],[0,188],[0,189],[0,190],[0,191],[0,192],[0,193],[0,194],[0,195],[0,196],[0,197],[0,198],[0,199],[0,200],[0,201],[0,202],[0,203],[0,204],[0,205],[0,206],[0,207],[0,208],[0,209],[0,210],[0,211],[0,212],[0,213],[0,214],[0,215],[0,216],[0,217],[0,218],[0,219],[0,220],[0,221],[0,222],[0,223],[0,224],[0,225],[0,226],[0,227],[0,228],[0,229],[0,230],[0,231],[0,232],[0,233],[0,234],[0,235],[0,236],[0,237],[0,238],[0,239],[0,240],[0,241],[0,242],[0,243],[0,244],[0,245],[0,246],[0,247],[0,248],[0,249],[0,250],[0,251],[0,252],[0,253],[0,254],[0,255],[0,256],[0,257],[0,258],[0,259],[0,260],[0,261],[0,262],[0,263],[0,264],[0,265],[0,266],[0,267],[0,268],[0,269],[0,270],[0,271],[0,272],[0,273],[0,274],[0,275],[0,276],[0,277],[0,278],[0,279],[0,280],[0,281],[0,282],[0,283],[0,284],[0,285],[0,286],[0,287],[0,288],[0,289],[0,290],[0,291],[0,292],[0,293],[0,294],[0,295],[0,296],[0,297],[0,298],[0,299],[0,300],[0,301],[0,302],[0,303],[0,304],[0,305],[0,306],[0,307],[0,308],[0,309],[0,310],[0,311],[0,312],[0,313],[0,314],[0,315],[0,316],[0,317],[0,318],[0,319],[0,320],[0,321],[0,322],[0,323],[0,324],[0,325],[0,326],[0,327],[0,328],[0,329],[0,330],[0,331],[0,332],[0,333],[0,334],[0,335],[0,336],[0,337],[0,338],[0,339],[0,340],[0,341],[0,342],[0,343],[0,344],[0,345],[0,346],[0,347],[0,348],[0,349],[0,350],[0,351],[0,352],[0,353],[0,354],[0,355],[0,356],[0,357],[0,358],[0,359],[0,360],[0,361],[0,362],[0,363],[0,364],[0,365],[0,366],[0,367],[0,368],[0,369],[0,370],[0,371],[0,372],[0,373],[0,374],[0,375],[0,376],[0,377],[0,378],[0,379],[0,380],[0,381],[0,382],[0,383],[0,384],[0,385],[0,386],[0,387],[0,388],[0,389],[0,390],[0,391],[0,392],[0,393],[0,394],[0,395],[0,396],[0,397],[0,398],[0,399],[0,400],[0,401],[0,402],[0,403],[0,404],[0,405],[0,406],[0,407],[0,408],[0,409],[0,410],[0,411],[0,412],[0,413],[0,414],[0,415],[0,416],[0,417],[0,418],[0,419],[0,420],[0,421],[0,422],[0,423],[0,424],[0,425],[0,426],[0,427],[0,428],[0,429],[0,430],[0,431],[0,432],[0,433],[0,434],[0,435],[0,436],[0,437],[0,438],[0,439],[0,440],[0,441],[0,442],[0,443],[0,444],[0,445],[0,446],[0,447],[0,448],[0,449],[0,450],[0,451],[0,452],[0,453],[0,454],[0,455],[0,456],[0,457],[0,458],[0,459],[0,460],[0,461],[0,462],[0,463],[0,464],[0,465],[0,466],[0,467],[0,468],[0,469],[0,470],[0,471],[0,472],[0,473],[0,474],[0,475],[0,476],[0,477],[0,478],[0,479],[0,480],[0,481],[0,482],[0,483],[0,484],[0,485],[0,486],[0,487],[0,488],[0,489],[0,490],[0,491],[0,492],[0,493],[0,494],[0,495],[0,496],[0,497],[0,498],[0,499],[0,500],[1,2],[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],[1,9],[1,10],[1,11],[1,12],[1,13],[1,14],[1,15],[1,16],[1,17],[1,18],[1,19],[1,20],[1,21],[1,22],[1,23],[1,24],[1,25],[1,26],[1,27],[1,28],[1,29],[1,30],[1,31],[1,32],[1,33],[1,34],[1,35],[1,36],[1,37],[1,38],[1,39],[1,40],[1,41],[1,42],[1,43],[1,44],[1,45],[1,46],[1,47],[1,48],[1,49],[1,50],[1,51],[1,52],[1,53],[1,54],[1,55],[1,56],[1,57],[1,58],[1,59],[1,60],[1,61],[1,62],[1,63],[1,64],[1,65],[1,66],[1,67],[1,68],[1,69],[1,70],[1,71],[1,72],[1,73],[1,74],[1,75],[1,76],[1,77],[1,78],[1,79],[1,80],[1,81],[1,82],[1,83],[1,84],[1,85],[1,86],[1,87],[1,88],[1,89],[1,90],[1,91],[1,92],[1,93],[1,94],[1,95],[1,96],[1,97],[1,98],[1,99],[1,100],[1,101],[1,102],[1,103],[1,104],[1,105],[1,106],[1,107],[1,108],[1,109],[1,110],[1,111],[1,112],[1,113],[1,114],[1,115],[1,116],[1,117],[1,118],[1,119],[1,120],[1,121],[1,122],[1,123],[1,124],[1,125],[1,126],[1,127],[1,128],[1,129],[1,130],[1,131],[1,132],[1,133],[1,134],[1,135],[1,136],[1,137],[1,138],[1,139],[1,140],[1,141],[1,142],[1,143],[1,144],[1,145],[1,146],[1,147],[1,148],[1,149],[1,150],[1,151],[1,152],[1,153],[1,154],[1,155],[1,156],[1,157],[1,158],[1,159],[1,160],[1,161],[1,162],[1,163],[1,164],[1,165],[1,166],[1,167],[1,168],[1,169],[1,170],[1,171],[1,172],[1,173],[1,174],[1,175],[1,176],[1,177],[1,178],[1,179],[1,180],[1,181],[1,182],[1,183],[1,184],[1,185],[1,186],[1,187],[1,188],[1,189],[1,190],[1,191],[1,192],[1,193],[1,194],[1,195],[1,196],[1,197],[1,198],[1,199],[1,200],[1,201],[1,202],[1,203],[1,204],[1,205],[1,206],[1,207],[1,208],[1,209],[1,210],[1,211],[1,212],[1,213],[1,214],[1,215],[1,216],[1,217],[1,218],[1,219],[1,220],[1,221],[1,222],[1,223],[1,224],[1,225],[1,226],[1,227],[1,228],[1,229],[1,230],[1,231],[1,232],[1,233],[1,234],[1,235],[1,236],[1,237],[1,238],[1,239],[1,240],[1,241],[1,242],[1,243],[1,244],[1,245],[1,246],[1,247],[1,248],[1,249],[1,250],[1,251],[1,252],[1,253],[1,254],[1,255],[1,256],[1,257],[1,258],[1,259],[1,260],[1,261],[1,262],[1,263],[1,264],[1,265],[1,266],[1,267],[1,268],[1,269],[1,270],[1,271],[1,272],[1,273],[1,274],[1,275],[1,276],[1,277],[1,278],[1,279],[1,280],[1,281],[1,282],[1,283],[1,284],[1,285],[1,286],[1,287],[1,288],[1,289],[1,290],[1,291],[1,292],[1,293],[1,294],[1,295],[1,296],[1,297],[1,298],[1,299],[1,300],[1,301],[1,302],[1,303],[1,304],[1,305],[1,306],[1,307],[1,308],[1,309],[1,310],[1,311],[1,312],[1,313],[1,314],[1,315],[1,316],[1,317],[1,318],[1,319],[1,320],[1,321],[1,322],[1,323],[1,324],[1,325],[1,326],[1,327],[1,328],[1,329],[1,330],[1,331],[1,332],[1,333],[1,334],[1,335],[1,336],[1,337],[1,338],[1,339],[1,340],[1,341],[1,342],[1,343],[1,344],[1,345],[1,346],[1,347],[1,348],[1,349],[1,350],[1,351],[1,352],[1,353],[1,354],[1,355],[1,356],[1,357],[1,358],[1,359],[1,360],[1,361],[1,362],[1,363],[1,364],[1,365],[1,366],[1,367],[1,368],[1,369],[1,370],[1,371],[1,372],[1,373],[1,374],[1,375],[1,376],[1,377],[1,378],[1,379],[1,380],[1,381],[1,382],[1,383],[1,384],[1,385],[1,386],[1,387],[1,388],[1,389],[1,390],[1,391],[1,392],[1,393],[1,394],[1,395],[1,396],[1,397],[1,398],[1,399],[1,400],[1,401],[1,402],[1,403],[1,404],[1,405],[1,406],[1,407],[1,408],[1,409],[1,410],[1,411],[1,412],[1,413],[1,414],[1,415],[1,416],[1,417],[1,418],[1,419],[1,420],[1,421],[1,422],[1,423],[1,424],[1,425],[1,426],[1,427],[1,428],[1,429],[1,430],[1,431],[1,432],[1,433],[1,434],[1,435],[1,436],[1,437],[1,438],[1,439],[1,440],[1,441],[1,442],[1,443],[1,444],[1,445],[1,446],[1,447],[1,448],[1,449],[1,450],[1,451],[1,452],[1,453],[1,454],[1,455],[1,456],[1,457],[1,458],[1,459],[1,460],[1,461],[1,462],[1,463],[1,464],[1,465],[1,466],[1,467],[1,468],[1,469],[1,470],[1,471],[1,472],[1,473],[1,474],[1,475],[1,476],[1,477],[1,478],[1,479],[1,480],[1,481],[1,482],[1,483],[1,484],[1,485],[1,486],[1,487],[1,488],[1,489],[1,490],[1,491],[1,492],[1,493],[1,494],[1,495],[1,496],[1,497],[1,498],[1,499],[1,500],[2,2],[2,3],[2,4],[2,5],[2,6],[2,7],[2,8],[2,9],[2,10],[2,11],[2,12],[2,13],[2,14],[2,15],[2,16],[2,17],[2,18],[2,19],[2,20],[2,21],[2,22],[2,23],[2,24],[2,25],[2,26],[2,27],[2,28],[2,29],[2,30],[2,31],[2,32],[2,33],[2,34],[2,35],[2,36],[2,37],[2,38],[2,39],[2,40],[2,41],[2,42],[2,43],[2,44],[2,45],[2,46],[2,47],[2,48],[2,49],[2,50],[2,51],[2,52],[2,53],[2,54],[2,55],[2,56],[2,57],[2,58],[2,59],[2,60],[2,61],[2,62],[2,63],[2,64],[2,65],[2,66],[2,67],[2,68],[2,69],[2,70],[2,71],[2,72],[2,73],[2,74],[2,75],[2,76],[2,77],[2,78],[2,79],[2,80],[2,81],[2,82],[2,83],[2,84],[2,85],[2,86],[2,87],[2,88],[2,89],[2,90],[2,91],[2,92],[2,93],[2,94],[2,95],[2,96],[2,97],[2,98],[2,99],[2,100],[2,101],[2,102],[2,103],[2,104],[2,105],[2,106],[2,107],[2,108],[2,109],[2,110],[2,111],[2,112],[2,113],[2,114],[2,115],[2,116],[2,117],[2,118],[2,119],[2,120],[2,121],[2,122],[2,123],[2,124],[2,125],[2,126],[2,127],[2,128],[2,129],[2,130],[2,131],[2,132],[2,133],[2,134],[2,135],[2,136],[2,137],[2,138],[2,139],[2,140],[2,141],[2,142],[2,143],[2,144],[2,145],[2,146],[2,147],[2,148],[2,149],[2,150],[2,151],[2,152],[2,153],[2,154],[2,155],[2,156],[2,157],[2,158],[2,159],[2,160],[2,161],[2,162],[2,163],[2,164],[2,165],[2,166],[2,167],[2,168],[2,169],[2,170],[2,171],[2,172],[2,173],[2,174],[2,175],[2,176],[2,177],[2,178],[2,179],[2,180],[2,181],[2,182],[2,183],[2,184],[2,185],[2,186],[2,187],[2,188],[2,189],[2,190],[2,191],[2,192],[2,193],[2,194],[2,195],[2,196],[2,197],[2,198],[2,199],[2,200],[2,201],[2,202],[2,203],[2,204],[2,205],[2,206],[2,207],[2,208],[2,209],[2,210],[2,211],[2,212],[2,213],[2,214],[2,215],[2,216],[2,217],[2,218],[2,219],[2,220],[2,221],[2,222],[2,223],[2,224],[2,225],[2,226],[2,227],[2,228],[2,229],[2,230],[2,231],[2,232],[2,233],[2,234],[2,235],[2,236],[2,237],[2,238],[2,239],[2,240],[2,241],[2,242],[2,243],[2,244],[2,245],[2,246],[2,247],[2,248],[2,249],[2,250],[2,251],[2,252],[2,253],[2,254],[2,255],[2,256],[2,257],[2,258],[2,259],[2,260],[2,261],[2,262],[2,263],[2,264],[2,265],[2,266],[2,267],[2,268],[2,269],[2,270],[2,271],[2,272],[2,273],[2,274],[2,275],[2,276],[2,277],[2,278],[2,279],[2,280],[2,281],[2,282],[2,283],[2,284],[2,285],[2,286],[2,287],[2,288],[2,289],[2,290],[2,291],[2,292],[2,293],[2,294],[2,295],[2,296],[2,297],[2,298],[2,299],[2,300],[2,301],[2,302],[2,303],[2,304],[2,305],[2,306],[2,307],[2,308],[2,309],[2,310],[2,311],[2,312],[2,313],[2,314],[2,315],[2,316],[2,317],[2,318],[2,319],[2,320],[2,321],[2,322],[2,323],[2,324],[2,325],[2,326],[2,327],[2,328],[2,329],[2,330],[2,331],[2,332],[2,333],[2,334],[2,335],[2,336],[2,337],[2,338],[2,339],[2,340],[2,341],[2,342],[2,343],[2,344],[2,345],[2,346],[2,347],[2,348],[2,349],[2,350],[2,351],[2,352],[2,353],[2,354],[2,355],[2,356],[2,357],[2,358],[2,359],[2,360],[2,361],[2,362],[2,363],[2,364],[2,365],[2,366],[2,367],[2,368],[2,369],[2,370],[2,371],[2,372],[2,373],[2,374],[2,375],[2,376],[2,377],[2,378],[2,379],[2,380],[2,381],[2,382],[2,383],[2,384],[2,385],[2,386],[2,387],[2,388],[2,389],[2,390],[2,391],[2,392],[2,393],[2,394],[2,395],[2,396],[2,397],[2,398],[2,399],[2,400],[2,401],[2,402],[2,403],[2,404],[2,405],[2,406],[2,407],[2,408],[2,409],[2,410],[2,411],[2,412],[2,413],[2,414],[2,415],[2,416],[2,417],[2,418],[2,419],[2,420],[2,421],[2,422],[2,423],[2,424],[2,425],[2,426],[2,427],[2,428],[2,429],[2,430],[2,431],[2,432],[2,433],[2,434],[2,435],[2,436],[2,437],[2,438],[2,439],[2,440],[2,441],[2,442],[2,443],[2,444],[2,445],[2,446],[2,447],[2,448],[2,449],[2,450],[2,451],[2,452],[2,453],[2,454],[2,455],[2,456],[2,457],[2,458],[2,459],[2,460],[2,461],[2,462],[2,463],[2,464],[2,465],[2,466],[2,467],[2,468],[2,469],[2,470],[2,471],[2,472],[2,473],[2,474],[2,475],[2,476],[2,477],[2,478],[2,479],[2,480],[2,481],[2,482],[2,483],[2,484],[2,485],[2,486],[2,487],[2,488],[2,489],[2,490],[2,491],[2,492],[2,493],[2,494],[2,495],[2,496],[2,497],[2,498],[2,499],[2,500],[3,2],[3,3],[3,4],[3,5],[3,6],[3,7],[3,8],[3,9],[3,10],[3,11],[3,12],[3,13],[3,14],[3,15],[3,16],[3,17],[3,18],[3,19],[3,20],[3,21],[3,22],[3,23],[3,24],[3,25],[3,26],[3,27],[3,28],[3,29],[3,30],[3,31],[3,32],[3,33],[3,34],[3,35],[3,36],[3,37],[3,38],[3,39],[3,40],[3,41],[3,42],[3,43],[3,44],[3,45],[3,46],[3,47],[3,48],[3,49],[3,50],[3,51],[3,52],[3,53],[3,54],[3,55],[3,56],[3,57],[3,58],[3,59],[3,60],[3,61],[3,62],[3,63],[3,64],[3,65],[3,66],[3,67],[3,68],[3,69],[3,70],[3,71],[3,72],[3,73],[3,74],[3,75],[3,76],[3,77],[3,78],[3,79],[3,80],[3,81],[3,82],[3,83],[3,84],[3,85],[3,86],[3,87],[3,88],[3,89],[3,90],[3,91],[3,92],[3,93],[3,94],[3,95],[3,96],[3,97],[3,98],[3,99],[3,100],[3,101],[3,102],[3,103],[3,104],[3,105],[3,106],[3,107],[3,108],[3,109],[3,110],[3,111],[3,112],[3,113],[3,114],[3,115],[3,116],[3,117],[3,118],[3,119],[3,120],[3,121],[3,122],[3,123],[3,124],[3,125],[3,126],[3,127],[3,128],[3,129],[3,130],[3,131],[3,132],[3,133],[3,134],[3,135],[3,136],[3,137],[3,138],[3,139],[3,140],[3,141],[3,142],[3,143],[3,144],[3,145],[3,146],[3,147],[3,148],[3,149],[3,150],[3,151],[3,152],[3,153],[3,154],[3,155],[3,156],[3,157],[3,158],[3,159],[3,160],[3,161],[3,162],[3,163],[3,164],[3,165],[3,166],[3,167],[3,168],[3,169],[3,170],[3,171],[3,172],[3,173],[3,174],[3,175],[3,176],[3,177],[3,178],[3,179],[3,180],[3,181],[3,182],[3,183],[3,184],[3,185],[3,186],[3,187],[3,188],[3,189],[3,190],[3,191],[3,192],[3,193],[3,194],[3,195],[3,196],[3,197],[3,198],[3,199],[3,200],[3,201],[3,202],[3,203],[3,204],[3,205],[3,206],[3,207],[3,208],[3,209],[3,210],[3,211],[3,212],[3,213],[3,214],[3,215],[3,216],[3,217],[3,218],[3,219],[3,220],[3,221],[3,222],[3,223],[3,224],[3,225],[3,226],[3,227],[3,228],[3,229],[3,230],[3,231],[3,232],[3,233],[3,234],[3,235],[3,236],[3,237],[3,238],[3,239],[3,240],[3,241],[3,242],[3,243],[3,244],[3,245],[3,246],[3,247],[3,248],[3,249],[3,250],[3,251],[3,252],[3,253],[3,254],[3,255],[3,256],[3,257],[3,258],[3,259],[3,260],[3,261],[3,262],[3,263],[3,264],[3,265],[3,266],[3,267],[3,268],[3,269],[3,270],[3,271],[3,272],[3,273],[3,274],[3,275],[3,276],[3,277],[3,278],[3,279],[3,280],[3,281],[3,282],[3,283],[3,284],[3,285],[3,286],[3,287],[3,288],[3,289],[3,290],[3,291],[3,292],[3,293],[3,294],[3,295],[3,296],[3,297],[3,298],[3,299],[3,300],[3,301],[3,302],[3,303],[3,304],[3,305],[3,306],[3,307],[3,308],[3,309],[3,310],[3,311],[3,312],[3,313],[3,314],[3,315],[3,316],[3,317],[3,318],[3,319],[3,320],[3,321],[3,322],[3,323],[3,324],[3,325],[3,326],[3,327],[3,328],[3,329],[3,330],[3,331],[3,332],[3,333],[3,334],[3,335],[3,336],[3,337],[3,338],[3,339],[3,340],[3,341],[3,342],[3,343],[3,344],[3,345],[3,346],[3,347],[3,348],[3,349],[3,350],[3,351],[3,352],[3,353],[3,354],[3,355],[3,356],[3,357],[3,358],[3,359],[3,360],[3,361],[3,362],[3,363],[3,364],[3,365],[3,366],[3,367],[3,368],[3,369],[3,370],[3,371],[3,372],[3,373],[3,374],[3,375],[3,376],[3,377],[3,378],[3,379],[3,380],[3,381],[3,382],[3,383],[3,384],[3,385],[3,386],[3,387],[3,388],[3,389],[3,390],[3,391],[3,392],[3,393],[3,394],[3,395],[3,396],[3,397],[3,398],[3,399],[3,400],[3,401],[3,402],[3,403],[3,404],[3,405],[3,406],[3,407],[3,408],[3,409],[3,410],[3,411],[3,412],[3,413],[3,414],[3,415],[3,416],[3,417],[3,418],[3,419],[3,420],[3,421],[3,422],[3,423],[3,424],[3,425],[3,426],[3,427],[3,428],[3,429],[3,430],[3,431],[3,432],[3,433],[3,434],[3,435],[3,436],[3,437],[3,438],[3,439],[3,440],[3,441],[3,442],[3,443],[3,444],[3,445],[3,446],[3,447],[3,448],[3,449],[3,450],[3,451],[3,452],[3,453],[3,454],[3,455],[3,456],[3,457],[3,458],[3,459],[3,460],[3,461],[3,462],[3,463],[3,464],[3,465],[3,466],[3,467],[3,468],[3,469],[3,470],[3,471],[3,472],[3,473],[3,474],[3,475],[3,476],[3,477],[3,478],[3,479],[3,480],[3,481],[3,482],[3,483],[3,484],[3,485],[3,486],[3,487],[3,488],[3,489],[3,490],[3,491],[3,492],[3,493],[3,494],[3,495],[3,496],[3,497],[3,498],[3,499],[3,500],[4,2],[4,3],[4,4],[4,5],[4,6],[4,7],[4,8],[4,9],[4,10],[4,11],[4,12],[4,13],[4,14],[4,15],[4,16],[4,17],[4,18],[4,19],[4,20],[4,21],[4,22],[4,23],[4,24],[4,25],[4,26],[4,27],[4,28],[4,29],[4,30],[4,31],[4,32],[4,33],[4,34],[4,35],[4,36],[4,37],[4,38],[4,39],[4,40],[4,41],[4,42],[4,43],[4,44],[4,45],[4,46],[4,47],[4,48],[4,49],[4,50],[4,51],[4,52],[4,53],[4,54],[4,55],[4,56],[4,57],[4,58],[4,59],[4,60],[4,61],[4,62],[4,63],[4,64],[4,65],[4,66],[4,67],[4,68],[4,69],[4,70],[4,71],[4,72],[4,73],[4,74],[4,75],[4,76],[4,77],[4,78],[4,79],[4,80],[4,81],[4,82],[4,83],[4,84],[4,85],[4,86],[4,87],[4,88],[4,89],[4,90],[4,91],[4,92],[4,93],[4,94],[4,95],[4,96],[4,97],[4,98],[4,99],[4,100],[4,101],[4,102],[4,103],[4,104],[4,105],[4,106],[4,107],[4,108],[4,109],[4,110],[4,111],[4,112],[4,113],[4,114],[4,115],[4,116],[4,117],[4,118],[4,119],[4,120],[4,121],[4,122],[4,123],[4,124],[4,125],[4,126],[4,127],[4,128],[4,129],[4,130],[4,131],[4,132],[4,133],[4,134],[4,135],[4,136],[4,137],[4,138],[4,139],[4,140],[4,141],[4,142],[4,143],[4,144],[4,145],[4,146],[4,147],[4,148],[4,149],[4,150],[4,151],[4,152],[4,153],[4,154],[4,155],[4,156],[4,157],[4,158],[4,159],[4,160],[4,161],[4,162],[4,163],[4,164],[4,165],[4,166],[4,167],[4,168],[4,169],[4,170],[4,171],[4,172],[4,173],[4,174],[4,175],[4,176],[4,177],[4,178],[4,179],[4,180],[4,181],[4,182],[4,183],[4,184],[4,185],[4,186],[4,187],[4,188],[4,189],[4,190],[4,191],[4,192],[4,193],[4,194],[4,195],[4,196],[4,197],[4,198],[4,199],[4,200],[4,201],[4,202],[4,203],[4,204],[4,205],[4,206],[4,207],[4,208],[4,209],[4,210],[4,211],[4,212],[4,213],[4,214],[4,215],[4,216],[4,217],[4,218],[4,219],[4,220],[4,221],[4,222],[4,223],[4,224],[4,225],[4,226],[4,227],[4,228],[4,229],[4,230],[4,231],[4,232],[4,233],[4,234],[4,235],[4,236],[4,237],[4,238],[4,239],[4,240],[4,241],[4,242],[4,243],[4,244],[4,245],[4,246],[4,247],[4,248],[4,249],[4,250],[4,251],[4,252],[4,253],[4,254],[4,255],[4,256],[4,257],[4,258],[4,259],[4,260],[4,261],[4,262],[4,263],[4,264],[4,265],[4,266],[4,267],[4,268],[4,269],[4,270],[4,271],[4,272],[4,273],[4,274],[4,275],[4,276],[4,277],[4,278],[4,279],[4,280],[4,281],[4,282],[4,283],[4,284],[4,285],[4,286],[4,287],[4,288],[4,289],[4,290],[4,291],[4,292],[4,293],[4,294],[4,295],[4,296],[4,297],[4,298],[4,299],[4,300],[4,301],[4,302],[4,303],[4,304],[4,305],[4,306],[4,307],[4,308],[4,309],[4,310],[4,311],[4,312],[4,313],[4,314],[4,315],[4,316],[4,317],[4,318],[4,319],[4,320],[4,321],[4,322],[4,323],[4,324],[4,325],[4,326],[4,327],[4,328],[4,329],[4,330],[4,331],[4,332],[4,333],[4,334],[4,335],[4,336],[4,337],[4,338],[4,339],[4,340],[4,341],[4,342],[4,343],[4,344],[4,345],[4,346],[4,347],[4,348],[4,349],[4,350],[4,351],[4,352],[4,353],[4,354],[4,355],[4,356],[4,357],[4,358],[4,359],[4,360],[4,361],[4,362],[4,363],[4,364],[4,365],[4,366],[4,367],[4,368],[4,369],[4,370],[4,371],[4,372],[4,373],[4,374],[4,375],[4,376],[4,377],[4,378],[4,379],[4,380],[4,381],[4,382],[4,383],[4,384],[4,385],[4,386],[4,387],[4,388],[4,389],[4,390],[4,391],[4,392],[4,393],[4,394],[4,395],[4,396],[4,397],[4,398],[4,399],[4,400],[4,401],[4,402],[4,403],[4,404],[4,405],[4,406],[4,407],[4,408],[4,409],[4,410],[4,411],[4,412],[4,413],[4,414],[4,415],[4,416],[4,417],[4,418],[4,419],[4,420],[4,421],[4,422],[4,423],[4,424],[4,425],[4,426],[4,427],[4,428],[4,429],[4,430],[4,431],[4,432],[4,433],[4,434],[4,435],[4,436],[4,437],[4,438],[4,439],[4,440],[4,441],[4,442],[4,443],[4,444],[4,445],[4,446],[4,447],[4,448],[4,449],[4,450],[4,451],[4,452],[4,453],[4,454],[4,455],[4,456],[4,457],[4,458],[4,459],[4,460],[4,461],[4,462],[4,463],[4,464],[4,465],[4,466],[4,467],[4,468],[4,469],[4,470],[4,471],[4,472],[4,473],[4,474],[4,475],[4,476],[4,477],[4,478],[4,479],[4,480],[4,481],[4,482],[4,483],[4,484],[4,485],[4,486],[4,487],[4,488],[4,489],[4,490],[4,491],[4,492],[4,493],[4,494],[4,495],[4,496],[4,497],[4,498],[4,499],[4,500],[5,2],[5,3],[5,4],[5,5],[5,6],[5,7],[5,8],[5,9],[5,10],[5,11],[5,12],[5,13],[5,14],[5,15],[5,16],[5,17],[5,18],[5,19],[5,20],[5,21],[5,22],[5,23],[5,24],[5,25],[5,26],[5,27],[5,28],[5,29],[5,30],[5,31],[5,32],[5,33],[5,34],[5,35],[5,36],[5,37],[5,38],[5,39],[5,40],[5,41],[5,42],[5,43],[5,44],[5,45],[5,46],[5,47],[5,48],[5,49],[5,50],[5,51],[5,52],[5,53],[5,54],[5,55],[5,56],[5,57],[5,58],[5,59],[5,60],[5,61],[5,62],[5,63],[5,64],[5,65],[5,66],[5,67],[5,68],[5,69],[5,70],[5,71],[5,72],[5,73],[5,74],[5,75],[5,76],[5,77],[5,78],[5,79],[5,80],[5,81],[5,82],[5,83],[5,84],[5,85],[5,86],[5,87],[5,88],[5,89],[5,90],[5,91],[5,92],[5,93],[5,94],[5,95],[5,96],[5,97],[5,98],[5,99],[5,100],[5,101],[5,102],[5,103],[5,104],[5,105],[5,106],[5,107],[5,108],[5,109],[5,110],[5,111],[5,112],[5,113],[5,114],[5,115],[5,116],[5,117],[5,118],[5,119],[5,120],[5,121],[5,122],[5,123],[5,124],[5,125],[5,126],[5,127],[5,128],[5,129],[5,130],[5,131],[5,132],[5,133],[5,134],[5,135],[5,136],[5,137],[5,138],[5,139],[5,140],[5,141],[5,142],[5,143],[5,144],[5,145],[5,146],[5,147],[5,148],[5,149],[5,150],[5,151],[5,152],[5,153],[5,154],[5,155],[5,156],[5,157],[5,158],[5,159],[5,160],[5,161],[5,162],[5,163],[5,164],[5,165],[5,166],[5,167],[5,168],[5,169],[5,170],[5,171],[5,172],[5,173],[5,174],[5,175],[5,176],[5,177],[5,178],[5,179],[5,180],[5,181],[5,182],[5,183],[5,184],[5,185],[5,186],[5,187],[5,188],[5,189],[5,190],[5,191],[5,192],[5,193],[5,194],[5,195],[5,196],[5,197],[5,198],[5,199],[5,200],[5,201],[5,202],[5,203],[5,204],[5,205],[5,206],[5,207],[5,208],[5,209],[5,210],[5,211],[5,212],[5,213],[5,214],[5,215],[5,216],[5,217],[5,218],[5,219],[5,220],[5,221],[5,222],[5,223],[5,224],[5,225],[5,226],[5,227],[5,228],[5,229],[5,230],[5,231],[5,232],[5,233],[5,234],[5,235],[5,236],[5,237],[5,238],[5,239],[5,240],[5,241],[5,242],[5,243],[5,244],[5,245],[5,246],[5,247],[5,248],[5,249],[5,250],[5,251],[5,252],[5,253],[5,254],[5,255],[5,256],[5,257],[5,258],[5,259],[5,260],[5,261],[5,262],[5,263],[5,264],[5,265],[5,266],[5,267],[5,268],[5,269],[5,270],[5,271],[5,272],[5,273],[5,274],[5,275],[5,276],[5,277],[5,278],[5,279],[5,280],[5,281],[5,282],[5,283],[5,284],[5,285],[5,286],[5,287],[5,288],[5,289],[5,290],[5,291],[5,292],[5,293],[5,294],[5,295],[5,296],[5,297],[5,298],[5,299],[5,300],[5,301],[5,302],[5,303],[5,304],[5,305],[5,306],[5,307],[5,308],[5,309],[5,310],[5,311],[5,312],[5,313],[5,314],[5,315],[5,316],[5,317],[5,318],[5,319],[5,320],[5,321],[5,322],[5,323],[5,324],[5,325],[5,326],[5,327],[5,328],[5,329],[5,330],[5,331],[5,332],[5,333],[5,334],[5,335],[5,336],[5,337],[5,338],[5,339],[5,340],[5,341],[5,342],[5,343],[5,344],[5,345],[5,346],[5,347],[5,348],[5,349],[5,350],[5,351],[5,352],[5,353],[5,354],[5,355],[5,356],[5,357],[5,358],[5,359],[5,360],[5,361],[5,362],[5,363],[5,364],[5,365],[5,366],[5,367],[5,368],[5,369],[5,370],[5,371],[5,372],[5,373],[5,374],[5,375],[5,376],[5,377],[5,378],[5,379],[5,380],[5,381],[5,382],[5,383],[5,384],[5,385],[5,386],[5,387],[5,388],[5,389],[5,390],[5,391],[5,392],[5,393],[5,394],[5,395],[5,396],[5,397],[5,398],[5,399],[5,400],[5,401],[5,402],[5,403],[5,404],[5,405],[5,406],[5,407],[5,408],[5,409],[5,410],[5,411],[5,412],[5,413],[5,414],[5,415],[5,416],[5,417],[5,418],[5,419],[5,420],[5,421],[5,422],[5,423],[5,424],[5,425],[5,426],[5,427],[5,428],[5,429],[5,430],[5,431],[5,432],[5,433],[5,434],[5,435],[5,436],[5,437],[5,438],[5,439],[5,440],[5,441],[5,442],[5,443],[5,444],[5,445],[5,446],[5,447],[5,448],[5,449],[5,450],[5,451],[5,452],[5,453],[5,454],[5,455],[5,456],[5,457],[5,458],[5,459],[5,460],[5,461],[5,462],[5,463],[5,464],[5,465],[5,466],[5,467],[5,468],[5,469],[5,470],[5,471],[5,472],[5,473],[5,474],[5,475],[5,476],[5,477],[5,478],[5,479],[5,480],[5,481],[5,482],[5,483],[5,484],[5,485],[5,486],[5,487],[5,488],[5,489],[5,490],[5,491],[5,492],[5,493],[5,494],[5,495],[5,496],[5,497],[5,498],[5,499],[5,500],[6,2],[6,3],[6,4],[6,5],[6,6],[6,7],[6,8],[6,9],[6,10],[6,11],[6,12],[6,13],[6,14],[6,15],[6,16],[6,17],[6,18],[6,19],[6,20],[6,21],[6,22],[6,23],[6,24],[6,25],[6,26],[6,27],[6,28],[6,29],[6,30],[6,31],[6,32],[6,33],[6,34],[6,35],[6,36],[6,37],[6,38],[6,39],[6,40],[6,41],[6,42],[6,43],[6,44],[6,45],[6,46],[6,47],[6,48],[6,49],[6,50],[6,51],[6,52],[6,53],[6,54],[6,55],[6,56],[6,57],[6,58],[6,59],[6,60],[6,61],[6,62],[6,63],[6,64],[6,65],[6,66],[6,67],[6,68],[6,69],[6,70],[6,71],[6,72],[6,73],[6,74],[6,75],[6,76],[6,77],[6,78],[6,79],[6,80],[6,81],[6,82],[6,83],[6,84],[6,85],[6,86],[6,87],[6,88],[6,89],[6,90],[6,91],[6,92],[6,93],[6,94],[6,95],[6,96],[6,97],[6,98],[6,99],[6,100],[6,101],[6,102],[6,103],[6,104],[6,105],[6,106],[6,107],[6,108],[6,109],[6,110],[6,111],[6,112],[6,113],[6,114],[6,115],[6,116],[6,117],[6,118],[6,119],[6,120],[6,121],[6,122],[6,123],[6,124],[6,125],[6,126],[6,127],[6,128],[6,129],[6,130],[6,131],[6,132],[6,133],[6,134],[6,135],[6,136],[6,137],[6,138],[6,139],[6,140],[6,141],[6,142],[6,143],[6,144],[6,145],[6,146],[6,147],[6,148],[6,149],[6,150],[6,151],[6,152],[6,153],[6,154],[6,155],[6,156],[6,157],[6,158],[6,159],[6,160],[6,161],[6,162],[6,163],[6,164],[6,165],[6,166],[6,167],[6,168],[6,169],[6,170],[6,171],[6,172],[6,173],[6,174],[6,175],[6,176],[6,177],[6,178],[6,179],[6,180],[6,181],[6,182],[6,183],[6,184],[6,185],[6,186],[6,187],[6,188],[6,189],[6,190],[6,191],[6,192],[6,193],[6,194],[6,195],[6,196],[6,197],[6,198],[6,199],[6,200],[6,201],[6,202],[6,203],[6,204],[6,205],[6,206],[6,207],[6,208],[6,209],[6,210],[6,211],[6,212],[6,213],[6,214],[6,215],[6,216],[6,217],[6,218],[6,219],[6,220],[6,221],[6,222],[6,223],[6,224],[6,225],[6,226],[6,227],[6,228],[6,229],[6,230],[6,231],[6,232],[6,233],[6,234],[6,235],[6,236],[6,237],[6,238],[6,239],[6,240],[6,241],[6,242],[6,243],[6,244],[6,245],[6,246],[6,247],[6,248],[6,249],[6,250],[6,251],[6,252],[6,253],[6,254],[6,255],[6,256],[6,257],[6,258],[6,259],[6,260],[6,261],[6,262],[6,263],[6,264],[6,265],[6,266],[6,267],[6,268],[6,269],[6,270],[6,271],[6,272],[6,273],[6,274],[6,275],[6,276],[6,277],[6,278],[6,279],[6,280],[6,281],[6,282],[6,283],[6,284],[6,285],[6,286],[6,287],[6,288],[6,289],[6,290],[6,291],[6,292],[6,293],[6,294],[6,295],[6,296],[6,297],[6,298],[6,299],[6,300],[6,301],[6,302],[6,303],[6,304],[6,305],[6,306],[6,307],[6,308],[6,309],[6,310],[6,311],[6,312],[6,313],[6,314],[6,315],[6,316],[6,317],[6,318],[6,319],[6,320],[6,321],[6,322],[6,323],[6,324],[6,325],[6,326],[6,327],[6,328],[6,329],[6,330],[6,331],[6,332],[6,333],[6,334],[6,335],[6,336],[6,337],[6,338],[6,339],[6,340],[6,341],[6,342],[6,343],[6,344],[6,345],[6,346],[6,347],[6,348],[6,349],[6,350],[6,351],[6,352],[6,353],[6,354],[6,355],[6,356],[6,357],[6,358],[6,359],[6,360],[6,361],[6,362],[6,363],[6,364],[6,365],[6,366],[6,367],[6,368],[6,369],[6,370],[6,371],[6,372],[6,373],[6,374],[6,375],[6,376],[6,377],[6,378],[6,379],[6,380],[6,381],[6,382],[6,383],[6,384],[6,385],[6,386],[6,387],[6,388],[6,389],[6,390],[6,391],[6,392],[6,393],[6,394],[6,395],[6,396],[6,397],[6,398],[6,399],[6,400],[6,401],[6,402],[6,403],[6,404],[6,405],[6,406],[6,407],[6,408],[6,409],[6,410],[6,411],[6,412],[6,413],[6,414],[6,415],[6,416],[6,417],[6,418],[6,419],[6,420],[6,421],[6,422],[6,423],[6,424],[6,425],[6,426],[6,427],[6,428],[6,429],[6,430],[6,431],[6,432],[6,433],[6,434],[6,435],[6,436],[6,437],[6,438],[6,439],[6,440],[6,441],[6,442],[6,443],[6,444],[6,445],[6,446],[6,447],[6,448],[6,449],[6,450],[6,451],[6,452],[6,453],[6,454],[6,455],[6,456],[6,457],[6,458],[6,459],[6,460],[6,461],[6,462],[6,463],[6,464],[6,465],[6,466],[6,467],[6,468],[6,469],[6,470],[6,471],[6,472],[6,473],[6,474],[6,475],[6,476],[6,477],[6,478],[6,479],[6,480],[6,481],[6,482],[6,483],[6,484],[6,485],[6,486],[6,487],[6,488],[6,489],[6,490],[6,491],[6,492],[6,493],[6,494],[6,495],[6,496],[6,497],[6,498],[6,499],[6,500],[7,2],[7,3],[7,4],[7,5],[7,6],[7,7],[7,8],[7,9],[7,10],[7,11],[7,12],[7,13],[7,14],[7,15],[7,16],[7,17],[7,18],[7,19],[7,20],[7,21],[7,22],[7,23],[7,24],[7,25],[7,26],[7,27],[7,28],[7,29],[7,30],[7,31],[7,32],[7,33],[7,34],[7,35],[7,36],[7,37],[7,38],[7,39],[7,40],[7,41],[7,42],[7,43],[7,44],[7,45],[7,46],[7,47],[7,48],[7,49],[7,50],[7,51],[7,52],[7,53],[7,54],[7,55],[7,56],[7,57],[7,58],[7,59],[7,60],[7,61],[7,62],[7,63],[7,64],[7,65],[7,66],[7,67],[7,68],[7,69],[7,70],[7,71],[7,72],[7,73],[7,74],[7,75],[7,76],[7,77],[7,78],[7,79],[7,80],[7,81],[7,82],[7,83],[7,84],[7,85],[7,86],[7,87],[7,88],[7,89],[7,90],[7,91],[7,92],[7,93],[7,94],[7,95],[7,96],[7,97],[7,98],[7,99],[7,100],[7,101],[7,102],[7,103],[7,104],[7,105],[7,106],[7,107],[7,108],[7,109],[7,110],[7,111],[7,112],[7,113],[7,114],[7,115],[7,116],[7,117],[7,118],[7,119],[7,120],[7,121],[7,122],[7,123],[7,124],[7,125],[7,126],[7,127],[7,128],[7,129],[7,130],[7,131],[7,132],[7,133],[7,134],[7,135],[7,136],[7,137],[7,138],[7,139],[7,140],[7,141],[7,142],[7,143],[7,144],[7,145],[7,146],[7,147],[7,148],[7,149],[7,150],[7,151],[7,152],[7,153],[7,154],[7,155],[7,156],[7,157],[7,158],[7,159],[7,160],[7,161],[7,162],[7,163],[7,164],[7,165],[7,166],[7,167],[7,168],[7,169],[7,170],[7,171],[7,172],[7,173],[7,174],[7,175],[7,176],[7,177],[7,178],[7,179],[7,180],[7,181],[7,182],[7,183],[7,184],[7,185],[7,186],[7,187],[7,188],[7,189],[7,190],[7,191],[7,192],[7,193],[7,194],[7,195],[7,196],[7,197],[7,198],[7,199],[7,200],[7,201],[7,202],[7,203],[7,204],[7,205],[7,206],[7,207],[7,208],[7,209],[7,210],[7,211],[7,212],[7,213],[7,214],[7,215],[7,216],[7,217],[7,218],[7,219],[7,220],[7,221],[7,222],[7,223],[7,224],[7,225],[7,226],[7,227],[7,228],[7,229],[7,230],[7,231],[7,232],[7,233],[7,234],[7,235],[7,236],[7,237],[7,238],[7,239],[7,240],[7,241],[7,242],[7,243],[7,244],[7,245],[7,246],[7,247],[7,248],[7,249],[7,250],[7,251],[7,252],[7,253],[7,254],[7,255],[7,256],[7,257],[7,258],[7,259],[7,260],[7,261],[7,262],[7,263],[7,264],[7,265],[7,266],[7,267],[7,268],[7,269],[7,270],[7,271],[7,272],[7,273],[7,274],[7,275],[7,276],[7,277],[7,278],[7,279],[7,280],[7,281],[7,282],[7,283],[7,284],[7,285],[7,286],[7,287],[7,288],[7,289],[7,290],[7,291],[7,292],[7,293],[7,294],[7,295],[7,296],[7,297],[7,298],[7,299],[7,300],[7,301],[7,302],[7,303],[7,304],[7,305],[7,306],[7,307],[7,308],[7,309],[7,310],[7,311],[7,312],[7,313],[7,314],[7,315],[7,316],[7,317],[7,318],[7,319],[7,320],[7,321],[7,322],[7,323],[7,324],[7,325],[7,326],[7,327],[7,328],[7,329],[7,330],[7,331],[7,332],[7,333],[7,334],[7,335],[7,336],[7,337],[7,338],[7,339],[7,340],[7,341],[7,342],[7,343],[7,344],[7,345],[7,346],[7,347],[7,348],[7,349],[7,350],[7,351],[7,352],[7,353],[7,354],[7,355],[7,356],[7,357],[7,358],[7,359],[7,360],[7,361],[7,362],[7,363],[7,364],[7,365],[7,366],[7,367],[7,368],[7,369],[7,370],[7,371],[7,372],[7,373],[7,374],[7,375],[7,376],[7,377],[7,378],[7,379],[7,380],[7,381],[7,382],[7,383],[7,384],[7,385],[7,386],[7,387],[7,388],[7,389],[7,390],[7,391],[7,392],[7,393],[7,394],[7,395],[7,396],[7,397],[7,398],[7,399],[7,400],[7,401],[7,402],[7,403],[7,404],[7,405],[7,406],[7,407],[7,408],[7,409],[7,410],[7,411],[7,412],[7,413],[7,414],[7,415],[7,416],[7,417],[7,418],[7,419],[7,420],[7,421],[7,422],[7,423],[7,424],[7,425],[7,426],[7,427],[7,428],[7,429],[7,430],[7,431],[7,432],[7,433],[7,434],[7,435],[7,436],[7,437],[7,438],[7,439],[7,440],[7,441],[7,442],[7,443],[7,444],[7,445],[7,446],[7,447],[7,448],[7,449],[7,450],[7,451],[7,452],[7,453],[7,454],[7,455],[7,456],[7,457],[7,458],[7,459],[7,460],[7,461],[7,462],[7,463],[7,464],[7,465],[7,466],[7,467],[7,468],[7,469],[7,470],[7,471],[7,472],[7,473],[7,474],[7,475],[7,476],[7,477],[7,478],[7,479],[7,480],[7,481],[7,482],[7,483],[7,484],[7,485],[7,486],[7,487],[7,488],[7,489],[7,490],[7,491],[7,492],[7,493],[7,494],[7,495],[7,496],[7,497],[7,498],[7,499],[7,500],[8,2],[8,3],[8,4],[8,5],[8,6],[8,7],[8,8],[8,9],[8,10],[8,11],[8,12],[8,13],[8,14],[8,15],[8,16],[8,17],[8,18],[8,19],[8,20],[8,21],[8,22],[8,23],[8,24],[8,25],[8,26],[8,27],[8,28],[8,29],[8,30],[8,31],[8,32],[8,33],[8,34],[8,35],[8,36],[8,37],[8,38],[8,39],[8,40],[8,41],[8,42],[8,43],[8,44],[8,45],[8,46],[8,47],[8,48],[8,49],[8,50],[8,51],[8,52],[8,53],[8,54],[8,55],[8,56],[8,57],[8,58],[8,59],[8,60],[8,61],[8,62],[8,63],[8,64],[8,65],[8,66],[8,67],[8,68],[8,69],[8,70],[8,71],[8,72],[8,73],[8,74],[8,75],[8,76],[8,77],[8,78],[8,79],[8,80],[8,81],[8,82],[8,83],[8,84],[8,85],[8,86],[8,87],[8,88],[8,89],[8,90],[8,91],[8,92],[8,93],[8,94],[8,95],[8,96],[8,97],[8,98],[8,99],[8,100],[8,101],[8,102],[8,103],[8,104],[8,105],[8,106],[8,107],[8,108],[8,109],[8,110],[8,111],[8,112],[8,113],[8,114],[8,115],[8,116],[8,117],[8,118],[8,119],[8,120],[8,121],[8,122],[8,123],[8,124],[8,125],[8,126],[8,127],[8,128],[8,129],[8,130],[8,131],[8,132],[8,133],[8,134],[8,135],[8,136],[8,137],[8,138],[8,139],[8,140],[8,141],[8,142],[8,143],[8,144],[8,145],[8,146],[8,147],[8,148],[8,149],[8,150],[8,151],[8,152],[8,153],[8,154],[8,155],[8,156],[8,157],[8,158],[8,159],[8,160],[8,161],[8,162],[8,163],[8,164],[8,165],[8,166],[8,167],[8,168],[8,169],[8,170],[8,171],[8,172],[8,173],[8,174],[8,175],[8,176],[8,177],[8,178],[8,179],[8,180],[8,181],[8,182],[8,183],[8,184],[8,185],[8,186],[8,187],[8,188],[8,189],[8,190],[8,191],[8,192],[8,193],[8,194],[8,195],[8,196],[8,197],[8,198],[8,199],[8,200],[8,201],[8,202],[8,203],[8,204],[8,205],[8,206],[8,207],[8,208],[8,209],[8,210],[8,211],[8,212],[8,213],[8,214],[8,215],[8,216],[8,217],[8,218],[8,219],[8,220],[8,221],[8,222],[8,223],[8,224],[8,225],[8,226],[8,227],[8,228],[8,229],[8,230],[8,231],[8,232],[8,233],[8,234],[8,235],[8,236],[8,237],[8,238],[8,239],[8,240],[8,241],[8,242],[8,243],[8,244],[8,245],[8,246],[8,247],[8,248],[8,249],[8,250],[8,251],[8,252],[8,253],[8,254],[8,255],[8,256],[8,257],[8,258],[8,259],[8,260],[8,261],[8,262],[8,263],[8,264],[8,265],[8,266],[8,267],[8,268],[8,269],[8,270],[8,271],[8,272],[8,273],[8,274],[8,275],[8,276],[8,277],[8,278],[8,279],[8,280],[8,281],[8,282],[8,283],[8,284],[8,285],[8,286],[8,287],[8,288],[8,289],[8,290],[8,291],[8,292],[8,293],[8,294],[8,295],[8,296],[8,297],[8,298],[8,299],[8,300],[8,301],[8,302],[8,303],[8,304],[8,305],[8,306],[8,307],[8,308],[8,309],[8,310],[8,311],[8,312],[8,313],[8,314],[8,315],[8,316],[8,317],[8,318],[8,319],[8,320],[8,321],[8,322],[8,323],[8,324],[8,325],[8,326],[8,327],[8,328],[8,329],[8,330],[8,331],[8,332],[8,333],[8,334],[8,335],[8,336],[8,337],[8,338],[8,339],[8,340],[8,341],[8,342],[8,343],[8,344],[8,345],[8,346],[8,347],[8,348],[8,349],[8,350],[8,351],[8,352],[8,353],[8,354],[8,355],[8,356],[8,357],[8,358],[8,359],[8,360],[8,361],[8,362],[8,363],[8,364],[8,365],[8,366],[8,367],[8,368],[8,369],[8,370],[8,371],[8,372],[8,373],[8,374],[8,375],[8,376],[8,377],[8,378],[8,379],[8,380],[8,381],[8,382],[8,383],[8,384],[8,385],[8,386],[8,387],[8,388],[8,389],[8,390],[8,391],[8,392],[8,393],[8,394],[8,395],[8,396],[8,397],[8,398],[8,399],[8,400],[8,401],[8,402],[8,403],[8,404],[8,405],[8,406],[8,407],[8,408],[8,409],[8,410],[8,411],[8,412],[8,413],[8,414],[8,415],[8,416],[8,417],[8,418],[8,419],[8,420],[8,421],[8,422],[8,423],[8,424],[8,425],[8,426],[8,427],[8,428],[8,429],[8,430],[8,431],[8,432],[8,433],[8,434],[8,435],[8,436],[8,437],[8,438],[8,439],[8,440],[8,441],[8,442],[8,443],[8,444],[8,445],[8,446],[8,447],[8,448],[8,449],[8,450],[8,451],[8,452],[8,453],[8,454],[8,455],[8,456],[8,457],[8,458],[8,459],[8,460],[8,461],[8,462],[8,463],[8,464],[8,465],[8,466],[8,467],[8,468],[8,469],[8,470],[8,471],[8,472],[8,473],[8,474],[8,475],[8,476],[8,477],[8,478],[8,479],[8,480],[8,481],[8,482],[8,483],[8,484],[8,485],[8,486],[8,487],[8,488],[8,489],[8,490],[8,491],[8,492],[8,493],[8,494],[8,495],[8,496],[8,497],[8,498],[8,499],[8,500],[21,2],[11,4],[11,4],[11,4],[11,4],[0,501],[0,502],[0,503],[1,501],[1,502],[1,503],[2,501],[2,502],[2,503],[3,501],[3,502],[3,503],[4,501],[4,502],[4,503],[5,501],[5,502],[5,503],[6,501],[6,502],[6,503],[7,501],[7,502],[7,503]],\"22,3\":[[21,3],[21,3],[21,3],[21,3],[21,3]],\"21,5\":[[30,5]],\"11,6\":[[29,4],[28,4],[29,3],[28,3]],\"10,10\":[[11,8],[11,8],[11,8],[11,8],[11,8],[11,8]],\"12,8\":[[11,8],[11,8]],\"11,5\":[[18,3],[19,3],[18,4],[19,4]]}", - "version": "1.4" -} diff --git a/quadratic-core/examples/startup_portfolio.grid b/quadratic-core/examples/startup_portfolio.grid deleted file mode 100644 index fde9c8e2b4..0000000000 --- a/quadratic-core/examples/startup_portfolio.grid +++ /dev/null @@ -1,2464 +0,0 @@ -{ - "sheets": [ - { - "name": "Sheet1", - "order": "a0", - "columns": [ - { "id": 15, "size": 122.95703125 }, - { "id": 4, "size": 129.81502939211464 }, - { "id": 3, "size": 119.37375559147 }, - { "id": 1, "size": 107.86122908054386 }, - { "id": 19, "size": 120.5090216592148 }, - { "id": 20, "size": 64.06815229791891 }, - { "id": 13, "size": 131.36854606677912 }, - { "id": 14, "size": 108.68073232211168 }, - { "id": 10, "size": 127.10245171645556 } - ], - "rows": [], - "cells": [ - { - "x": 0, - "y": 0, - "type": "TEXT", - "value": "Portfolio Valuation analysis by revenue multiple", - "last_modified": "2022-05-11T16:27:28.266Z" - }, - { "x": 0, "y": 2, "type": "TEXT", "value": "Startup portfolio", "last_modified": "2022-05-11T16:44:34.975Z" }, - { "x": 0, "y": 4, "type": "TEXT", "value": "Name", "last_modified": "2022-05-11T16:44:34.975Z" }, - { "x": 0, "y": 6, "type": "TEXT", "value": "Airtable", "last_modified": "2022-05-11T16:44:34.975Z" }, - { "x": 0, "y": 7, "type": "TEXT", "value": "Figma", "last_modified": "2022-05-12T17:32:06.440Z" }, - { "x": 0, "y": 8, "type": "TEXT", "value": "Databricks", "last_modified": "2022-05-12T17:33:17.712Z" }, - { "x": 0, "y": 9, "type": "TEXT", "value": "Alchemy", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 0, "y": 10, "type": "TEXT", "value": "FiveTran", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 0, "y": 11, "type": "TEXT", "value": "Starburst", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 0, "y": 12, "type": "TEXT", "value": "JumpCloud", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 0, "y": 13, "type": "TEXT", "value": "Redis Labs", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 0, "y": 14, "type": "TEXT", "value": "Cognite", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 0, "y": 15, "type": "TEXT", "value": "YugaByte", "last_modified": "2022-05-12T22:36:51.022Z" }, - { "x": 1, "y": 4, "type": "TEXT", "value": "Amount", "last_modified": "2022-05-11T16:44:34.975Z" }, - { "x": 1, "y": 6, "type": "TEXT", "value": "10000000", "last_modified": "2022-05-12T23:19:46.414Z" }, - { "x": 1, "y": 7, "type": "TEXT", "value": "8000000", "last_modified": "2022-05-12T23:12:37.579Z" }, - { "x": 1, "y": 8, "type": "TEXT", "value": "23000000", "last_modified": "2022-05-12T23:12:24.540Z" }, - { "x": 1, "y": 9, "type": "TEXT", "value": "15000000", "last_modified": "2022-05-12T23:12:33.508Z" }, - { "x": 1, "y": 10, "type": "TEXT", "value": "22000000", "last_modified": "2022-05-12T23:12:42.531Z" }, - { "x": 1, "y": 11, "type": "TEXT", "value": "5000000", "last_modified": "2022-05-12T23:12:45.704Z" }, - { "x": 1, "y": 12, "type": "TEXT", "value": "17000000", "last_modified": "2022-05-12T23:12:53.187Z" }, - { "x": 1, "y": 13, "type": "TEXT", "value": "10000000", "last_modified": "2022-05-12T23:13:00.561Z" }, - { "x": 1, "y": 14, "type": "TEXT", "value": "5000000", "last_modified": "2022-05-12T23:13:06.227Z" }, - { "x": 1, "y": 15, "type": "TEXT", "value": "18000000", "last_modified": "2022-05-12T23:13:13.550Z" }, - { "x": 2, "y": 4, "type": "TEXT", "value": "Date", "last_modified": "2023-02-17T00:48:34.426Z" }, - { "x": 2, "y": 6, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T23:13:17.789Z" }, - { "x": 2, "y": 7, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T17:40:21.878Z" }, - { "x": 2, "y": 8, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T17:40:35.451Z" }, - { "x": 2, "y": 9, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T17:40:36.012Z" }, - { "x": 2, "y": 10, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T17:40:36.421Z" }, - { "x": 2, "y": 11, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T17:40:37.096Z" }, - { "x": 2, "y": 12, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T17:40:37.600Z" }, - { "x": 2, "y": 13, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T17:40:38.006Z" }, - { "x": 2, "y": 14, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T17:40:38.614Z" }, - { "x": 2, "y": 15, "type": "TEXT", "value": "1/1/2021", "last_modified": "2022-05-12T17:40:39.083Z" }, - { "x": 3, "y": 4, "type": "TEXT", "value": "Revenue", "last_modified": "2022-05-11T16:44:34.975Z" }, - { "x": 3, "y": 6, "type": "TEXT", "value": "92000000", "last_modified": "2022-05-12T17:40:52.543Z" }, - { "x": 3, "y": 7, "type": "TEXT", "value": "51000000", "last_modified": "2022-05-12T22:32:25.399Z" }, - { "x": 3, "y": 8, "type": "TEXT", "value": "813000000", "last_modified": "2022-05-12T22:32:45.387Z" }, - { "x": 3, "y": 9, "type": "TEXT", "value": "800000000", "last_modified": "2022-05-14T15:37:32.352Z" }, - { "x": 3, "y": 10, "type": "TEXT", "value": "160000000", "last_modified": "2022-05-12T22:34:55.536Z" }, - { "x": 3, "y": 11, "type": "TEXT", "value": "66000000", "last_modified": "2022-05-12T22:35:19.653Z" }, - { "x": 3, "y": 12, "type": "TEXT", "value": "47000000", "last_modified": "2022-05-12T22:35:45.695Z" }, - { "x": 3, "y": 13, "type": "TEXT", "value": "150000000", "last_modified": "2022-05-14T15:37:26.034Z" }, - { "x": 3, "y": 14, "type": "TEXT", "value": "118000000", "last_modified": "2022-05-12T22:36:32.494Z" }, - { "x": 3, "y": 15, "type": "TEXT", "value": "110000000", "last_modified": "2022-05-14T15:37:14.349Z" }, - { "x": 4, "y": 4, "type": "TEXT", "value": "Valuation", "last_modified": "2022-05-11T16:44:34.975Z" }, - { "x": 4, "y": 6, "type": "TEXT", "value": "11000000000", "last_modified": "2022-05-12T17:35:44.556Z" }, - { "x": 4, "y": 7, "type": "TEXT", "value": "10000000000", "last_modified": "2022-05-12T17:38:08.595Z" }, - { "x": 4, "y": 8, "type": "TEXT", "value": "38000000000", "last_modified": "2022-05-12T17:38:43.902Z" }, - { "x": 4, "y": 9, "type": "TEXT", "value": "1020000000", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 4, "y": 10, "type": "TEXT", "value": "5600000000", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 4, "y": 11, "type": "TEXT", "value": "3350000000", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 4, "y": 12, "type": "TEXT", "value": "2620000000", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 4, "y": 13, "type": "TEXT", "value": "2000000000", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 4, "y": 14, "type": "TEXT", "value": "1500000000", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 4, "y": 15, "type": "TEXT", "value": "1300000000", "last_modified": "2022-05-12T17:39:57.316Z" }, - { "x": 5, "y": 4, "type": "TEXT", "value": "Paid multiple", "last_modified": "2022-05-11T16:44:34.975Z" }, - { - "x": 5, - "y": 6, - "type": "PYTHON", - "value": "119.5652173913043478260869565", - "python_code": "\nresult = []\nfor i in range(0, 10):\n result.append(\n \"{:}\".format(c(4, 6 + i) / c(3, 6 + i))\n )\nresult", - "last_modified": "2023-03-21T19:54:06.210Z", - "python_output": "", - "array_cells": [ - [5, 6], - [5, 7], - [5, 8], - [5, 9], - [5, 10], - [5, 11], - [5, 12], - [5, 13], - [5, 14], - [5, 15] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "['119.5652173913043478260869565', '196.0784313725490196078431373', '46.74046740467404674046740467', '1.275', '35', '50.75757575757575757575757576', '55.74468085106382978723404255', '13.33333333333333333333333333', '12.71186440677966101694915254', '11.81818181818181818181818182']", - "cells_accessed": [ - [4, 6], - [3, 6], - [4, 7], - [3, 7], - [4, 8], - [3, 8], - [4, 9], - [3, 9], - [4, 10], - [3, 10], - [4, 11], - [3, 11], - [4, 12], - [3, 12], - [4, 13], - [3, 13], - [4, 14], - [3, 14], - [4, 15], - [3, 15] - ], - "array_output": [ - "119.5652173913043478260869565", - "196.0784313725490196078431373", - "46.74046740467404674046740467", - "1.275", - "35", - "50.75757575757575757575757576", - "55.74468085106382978723404255", - "13.33333333333333333333333333", - "12.71186440677966101694915254", - "11.81818181818181818181818182" - ], - "formatted_code": "\nresult = []\nfor i in range(0, 10):\n result.append(\n \"{:}\".format(c(4, 6 + i) / c(3, 6 + i))\n )\nresult\n", - "error_span": null - } - }, - { - "x": 5, - "y": 7, - "type": "COMPUTED", - "value": "196.0784313725490196078431373", - "last_modified": "2023-03-21T19:54:06.210Z" - }, - { - "x": 5, - "y": 8, - "type": "COMPUTED", - "value": "46.74046740467404674046740467", - "last_modified": "2023-03-21T19:54:06.210Z" - }, - { "x": 5, "y": 9, "type": "COMPUTED", "value": "1.275", "last_modified": "2023-03-21T19:54:06.210Z" }, - { "x": 5, "y": 10, "type": "COMPUTED", "value": "35", "last_modified": "2023-03-21T19:54:06.210Z" }, - { - "x": 5, - "y": 11, - "type": "COMPUTED", - "value": "50.75757575757575757575757576", - "last_modified": "2023-03-21T19:54:06.210Z" - }, - { - "x": 5, - "y": 12, - "type": "COMPUTED", - "value": "55.74468085106382978723404255", - "last_modified": "2023-03-21T19:54:06.210Z" - }, - { - "x": 5, - "y": 13, - "type": "COMPUTED", - "value": "13.33333333333333333333333333", - "last_modified": "2023-03-21T19:54:06.210Z" - }, - { - "x": 5, - "y": 14, - "type": "COMPUTED", - "value": "12.71186440677966101694915254", - "last_modified": "2023-03-21T19:54:06.210Z" - }, - { - "x": 5, - "y": 15, - "type": "COMPUTED", - "value": "11.81818181818181818181818182", - "last_modified": "2023-03-21T19:54:06.210Z" - }, - { "x": 7, "y": 2, "type": "TEXT", "value": "Public market comps", "last_modified": "2022-05-12T22:51:41.212Z" }, - { "x": 7, "y": 4, "type": "TEXT", "value": "Ticker", "last_modified": "2022-05-11T16:47:43.219Z" }, - { "x": 7, "y": 6, "type": "TEXT", "value": "SNOW", "last_modified": "2023-02-17T00:51:43.664Z" }, - { "x": 7, "y": 7, "type": "TEXT", "value": "ADBE", "last_modified": "2022-05-12T18:51:47.993Z" }, - { "x": 7, "y": 8, "type": "TEXT", "value": "DDOG", "last_modified": "2022-05-12T18:51:58.179Z" }, - { "x": 7, "y": 9, "type": "TEXT", "value": "COIN", "last_modified": "2022-05-12T22:41:12.241Z" }, - { "x": 7, "y": 10, "type": "TEXT", "value": "INFA", "last_modified": "2022-05-12T22:42:46.350Z" }, - { "x": 7, "y": 11, "type": "TEXT", "value": "DOMO", "last_modified": "2022-05-12T22:43:11.315Z" }, - { "x": 7, "y": 12, "type": "TEXT", "value": "OKTA", "last_modified": "2022-05-12T22:43:47.094Z" }, - { "x": 7, "y": 13, "type": "TEXT", "value": "ORCL", "last_modified": "2022-05-12T22:44:36.850Z" }, - { "x": 7, "y": 14, "type": "TEXT", "value": "DOCN", "last_modified": "2022-05-12T22:45:02.343Z" }, - { "x": 7, "y": 15, "type": "TEXT", "value": "ORCL", "last_modified": "2022-05-12T22:45:40.301Z" }, - { "x": 8, "y": 4, "type": "TEXT", "value": "Name", "last_modified": "2022-05-12T18:52:46.093Z" }, - { - "x": 8, - "y": 6, - "type": "PYTHON", - "value": "Snowflake Inc.", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 6)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:54:12.884Z", - "python_output": "", - "array_cells": [ - [8, 6], - [9, 6], - [10, 6], - [11, 6] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": " 0 1 2 3\n0 Snowflake Inc. 1860421000.0 43567152000.0 23.41789949694182", - "cells_accessed": [[7, 6]], - "array_output": [["Snowflake Inc.", "1860421000.0", "43567152000.0", "23.41789949694182"]], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 6)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - } - }, - { - "x": 8, - "y": 7, - "type": "PYTHON", - "value": "Adobe Inc.", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 7)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:54:22.347Z", - "python_output": "", - "array_cells": [ - [8, 7], - [9, 7], - [10, 7], - [11, 7] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": " 0 1 2 3\n0 Adobe Inc. 17606000000.0 166407958362.24 9.45177543804612", - "cells_accessed": [[7, 7]], - "array_output": [["Adobe Inc.", "17606000000.0", "166407958362.24", "9.45177543804612"]], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 7)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - } - }, - { - "x": 8, - "y": 8, - "type": "PYTHON", - "value": "Datadog, Inc. Class ", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 8)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:54:26.458Z", - "python_output": "", - "array_cells": [ - [8, 8], - [9, 8], - [10, 8], - [11, 8] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": " 0 1 2 3\n0 Datadog, Inc. Class 1675100000.0 21180114934.109997 12.644089865745327", - "cells_accessed": [[7, 8]], - "array_output": [["Datadog, Inc. Class ", "1675100000.0", "21180114934.109997", "12.644089865745327"]], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 8)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - } - }, - { - "x": 8, - "y": 9, - "type": "PYTHON", - "value": "Coinbase Global, Inc", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 9)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:54:33.553Z", - "python_output": "", - "array_cells": [ - [8, 9], - [9, 9], - [10, 9], - [11, 9] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": " 0 1 2 3\n0 Coinbase Global, Inc 3194208000.0 17392936523.04 5.4451483820214595", - "cells_accessed": [[7, 9]], - "array_output": [["Coinbase Global, Inc", "3194208000.0", "17392936523.04", "5.4451483820214595"]], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 9)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - } - }, - { - "x": 8, - "y": 10, - "type": "PYTHON", - "value": "Informatica Inc.", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 10)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:55:12.638Z", - "python_output": "", - "array_cells": [ - [8, 10], - [9, 10], - [10, 10], - [11, 10] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": " 0 1 2 3\n0 Informatica Inc. 1505118000.0 4563793430.91 3.0321831450490926", - "cells_accessed": [[7, 10]], - "array_output": [["Informatica Inc.", "1505118000.0", "4563793430.91", "3.0321831450490926"]], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 10)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name[:20],\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - }, - "dependent_cells": [[7, 10]] - }, - { - "x": 8, - "y": 11, - "type": "PYTHON", - "value": "Domo, Inc. Class B Common Stock", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 11)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:55:18.010Z", - "python_output": "", - "array_cells": [ - [8, 11], - [9, 11], - [10, 11], - [11, 11] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": " 0 ... 3\n0 Domo, Inc. Class B Common Stock ... 1.4048398622138094\n\n[1 rows x 4 columns]", - "cells_accessed": [[7, 11]], - "array_output": [["Domo, Inc. Class B Common Stock", "299014000.0", "420066786.56", "1.4048398622138094"]], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 11)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - }, - "dependent_cells": [[7, 11]] - }, - { - "x": 8, - "y": 12, - "type": "PYTHON", - "value": "Okta, Inc. Class A Common Stock", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 12)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nprint(stock_financials_json)\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:57:07.476Z", - "python_output": "{'results': [{'financials': {'comprehensive_income': {'comprehensive_income_loss_attributable_to_parent': {'label': 'Comprehensive Income/Loss Attributable To Parent', 'value': -225282000.0, 'unit': 'USD', 'order': 300}, 'comprehensive_income_loss': {'label': 'Comprehensive Income/Loss', 'value': -225282000.0, 'unit': 'USD', 'order': 100}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 200}, 'other_comprehensive_income_loss': {'label': 'Other Comprehensive Income/Loss', 'value': -3971000.0, 'unit': 'USD', 'order': 400}}, 'income_statement': {'operating_expenses': {'label': 'Operating Expenses', 'value': 439562000.0, 'unit': 'USD', 'order': 1000}, 'income_tax_expense_benefit': {'label': 'Income Tax Expense/Benefit', 'value': 667000, 'unit': 'USD', 'order': 2200}, 'basic_earnings_per_share': {'label': 'Basic Earnings Per Share', 'value': -1.44, 'unit': 'USD / shares', 'order': 4200}, 'income_loss_from_continuing_operations_after_tax': {'label': 'Income/Loss From Continuing Operations After Tax', 'value': -221311000.0, 'unit': 'USD', 'order': 1400}, 'gross_profit': {'label': 'Gross Profit', 'value': 241006000.0, 'unit': 'USD', 'order': 800}, 'diluted_earnings_per_share': {'label': 'Diluted Earnings Per Share', 'value': -1.44, 'unit': 'USD / shares', 'order': 4300}, 'income_loss_from_continuing_operations_before_tax': {'label': 'Income/Loss From Continuing Operations Before Tax', 'value': -220644000.0, 'unit': 'USD', 'order': 1500}, 'operating_income_loss': {'label': 'Operating Income/Loss', 'value': -198556000.0, 'unit': 'USD', 'order': 1100}, 'revenues': {'label': 'Revenues', 'value': 350680000.0, 'unit': 'USD', 'order': 100}, 'net_income_loss_attributable_to_noncontrolling_interest': {'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 3300}, 'interest_expense_operating': {'label': 'Interest Expense, Operating', 'value': 23144000.0, 'unit': 'USD', 'order': 2700}, 'net_income_loss': {'label': 'Net Income/Loss', 'value': -221311000.0, 'unit': 'USD', 'order': 3200}, 'preferred_stock_dividends_and_other_adjustments': {'label': 'Preferred Stock Dividends And Other Adjustments', 'value': 0, 'unit': 'USD', 'order': 3900}, 'net_income_loss_attributable_to_parent': {'label': 'Net Income/Loss Attributable To Parent', 'value': -221311000.0, 'unit': 'USD', 'order': 3500}, 'cost_of_revenue': {'label': 'Cost Of Revenue', 'value': 109674000.0, 'unit': 'USD', 'order': 300}, 'net_income_loss_available_to_common_stockholders_basic': {'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'value': -221311000.0, 'unit': 'USD', 'order': 3700}, 'costs_and_expenses': {'label': 'Costs And Expenses', 'value': 571324000.0, 'unit': 'USD', 'order': 600}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'value': 0, 'unit': 'USD', 'order': 3800}, 'benefits_costs_expenses': {'label': 'Benefits Costs and Expenses', 'value': 571324000.0, 'unit': 'USD', 'order': 200}}, 'balance_sheet': {'current_liabilities': {'label': 'Current Liabilities', 'value': 988166000.0, 'unit': 'USD', 'order': 700}, 'equity_attributable_to_noncontrolling_interest': {'label': 'Equity Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 1500}, 'other_than_fixed_noncurrent_assets': {'label': 'Other Than Fixed Noncurrent Assets', 'value': 6083354000.0, 'unit': 'USD', 'order': 500}, 'noncurrent_liabilities': {'label': 'Noncurrent Liabilities', 'value': 2024252000.0, 'unit': 'USD', 'order': 800}, 'fixed_assets': {'label': 'Fixed Assets', 'value': 60751000.0, 'unit': 'USD', 'order': 400}, 'assets': {'label': 'Assets', 'value': 8996973000.0, 'unit': 'USD', 'order': 100}, 'liabilities': {'label': 'Liabilities', 'value': 3012418000.0, 'unit': 'USD', 'order': 600}, 'noncurrent_assets': {'label': 'Noncurrent Assets', 'value': 6144105000.0, 'unit': 'USD', 'order': 300}, 'equity': {'label': 'Equity', 'value': 5984555000.0, 'unit': 'USD', 'order': 1400}, 'liabilities_and_equity': {'label': 'Liabilities And Equity', 'value': 8996973000.0, 'unit': 'USD', 'order': 1900}, 'current_assets': {'label': 'Current Assets', 'value': 2852868000.0, 'unit': 'USD', 'order': 200}, 'equity_attributable_to_parent': {'label': 'Equity Attributable To Parent', 'value': 5984555000.0, 'unit': 'USD', 'order': 1600}}, 'cash_flow_statement': {}}, 'start_date': '2021-08-01', 'end_date': '2021-10-31', 'filing_date': '2021-12-02', 'cik': '0001660134', 'company_name': 'Okta, Inc.', 'fiscal_period': 'Q3', 'fiscal_year': '2022', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-21-000026', 'source_filing_file_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-21-000026/files/okta-20211031_htm.xml'}], 'status': 'OK', 'request_id': 'c26140ceab0fd97f5d9cc644eea44717', 'count': 1, 'next_url': 'https://api.polygon.io/vX/reference/financials?cursor=YXA9MjAyMTEwMzEmYXM9MDAwMTY2MDEzNC0yMS0wMDAwMjYmZW50aXRpZXMuY29tcGFueV9kYXRhLnRpY2tlcj1PS1RBJmhhc194YnJsPXRydWUmbGltaXQ9MSZzb3J0PXBlcmlvZF9vZl9yZXBvcnRfZGF0ZSZ0eXBlPTEwLVE'}\n", - "array_cells": [ - [8, 12], - [9, 12], - [10, 12], - [11, 12] - ], - "evaluation_result": { - "success": true, - "std_out": "{'results': [{'id': '0001660134:TTM', 'start_date': '2022-02-01', 'end_date': '2023-01-31', 'filing_date': '2023-03-03', 'timeframe': 'ttm', 'fiscal_period': 'TTM', 'fiscal_year': '2023', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-23-000013', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001660134-23-000013/files/okta-20230131_htm.xml', 'financials': {'cash_flow_statement': {'net_cash_flow_from_financing_activities_continuing': {'value': 48000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'exchange_gains_losses': {'value': -6000000.0, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow_from_operating_activities': {'value': 86000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_operating_activities_continuing': {'value': 86000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities': {'value': -130000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_continuing': {'value': 4000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities': {'value': 48000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_investing_activities_continuing': {'value': -130000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow': {'value': -2000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}}, 'balance_sheet': {'noncurrent_liabilities': {'value': 2376000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity_attributable_to_parent': {'value': 5466000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'liabilities_and_equity': {'value': 9307000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'fixed_assets': {'value': 59000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'current_liabilities': {'value': 1465000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'assets': {'value': 9307000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'other_than_fixed_noncurrent_assets': {'value': 6019000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'liabilities': {'value': 3841000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'equity': {'value': 5466000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'current_assets': {'value': 3229000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'noncurrent_assets': {'value': 6078000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss_attributable_to_parent': {'value': -836000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss': {'value': -836000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss': {'value': -21000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -21000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}}, 'income_statement': {'gross_profit': {'value': 1312000000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'income_loss_from_continuing_operations_after_tax': {'value': -815000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'revenues': {'value': 1858000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'costs_and_expenses': {'value': 2659000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'net_income_loss': {'value': -815000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'income_tax_expense_benefit_current': {'value': 7000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Current', 'order': 2300}, 'net_income_loss_attributable_to_parent': {'value': -815000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'diluted_earnings_per_share': {'value': -5.16, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -815000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'benefits_costs_expenses': {'value': 2659000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'cost_of_revenue': {'value': 546000000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'income_tax_expense_benefit': {'value': 14000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'interest_expense_operating': {'value': 11000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_loss_from_continuing_operations_before_tax': {'value': -801000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'basic_earnings_per_share': {'value': -5.16, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'operating_income_loss': {'value': -812000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'operating_expenses': {'value': 2124000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'income_tax_expense_benefit_deferred': {'value': 7000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}}}}, {'id': '0001660134:2023:Q4', 'start_date': '2022-11-01', 'end_date': '2023-01-31', 'timeframe': 'quarterly', 'fiscal_period': 'Q4', 'fiscal_year': '2023', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'financials': {'balance_sheet': {'other_than_fixed_noncurrent_assets': {'value': 6019000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'liabilities_and_equity': {'value': 9307000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'assets': {'value': 9307000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'liabilities': {'value': 3841000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'equity': {'value': 5466000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'current_assets': {'value': 3229000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'noncurrent_assets': {'value': 6078000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'noncurrent_liabilities': {'value': 2376000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'current_liabilities': {'value': 1465000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'fixed_assets': {'value': 59000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_parent': {'value': 5466000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}}, 'cash_flow_statement': {'net_cash_flow_continuing': {'value': 7896000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities_continuing': {'value': 14435000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': -82777000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_financing_activities': {'value': 14435000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_investing_activities': {'value': -82777000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities': {'value': 76238000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'exchange_gains_losses': {'value': 3747000.0, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow': {'value': 11643000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_operating_activities_continuing': {'value': 76238000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}}, 'income_statement': {'benefits_costs_expenses': {'value': 658930000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_loss_from_continuing_operations_before_tax': {'value': -148722000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'interest_expense_operating': {'value': 2412000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'diluted_earnings_per_share': {'value': -0.9500000000000002, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss_attributable_to_parent': {'value': -152918000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'cost_of_revenue': {'value': 139488000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'operating_expenses': {'value': 528370000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'income_tax_expense_benefit': {'value': 4196000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'basic_earnings_per_share': {'value': -0.9500000000000002, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'costs_and_expenses': {'value': 658930000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'operating_income_loss': {'value': -157650000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss': {'value': -152918000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'income_loss_from_continuing_operations_after_tax': {'value': -152918000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'gross_profit': {'value': 370720000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -152918000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'revenues': {'value': 510208000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}}, 'comprehensive_income': {'comprehensive_income_loss': {'value': -129863000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': -129863000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss': {'value': 23055000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}}}}, {'id': '0001660134:2023:FY', 'start_date': '2022-02-01', 'end_date': '2023-01-31', 'filing_date': '2023-03-03', 'timeframe': 'annual', 'fiscal_period': 'FY', 'fiscal_year': '2023', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-23-000013', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001660134-23-000013/files/okta-20230131_htm.xml', 'financials': {'balance_sheet': {'liabilities_and_equity': {'value': 9307000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity_attributable_to_parent': {'value': 5466000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'other_than_fixed_noncurrent_assets': {'value': 6019000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'liabilities': {'value': 3841000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'current_liabilities': {'value': 1465000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'current_assets': {'value': 3229000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity': {'value': 5466000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'fixed_assets': {'value': 59000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'assets': {'value': 9307000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_assets': {'value': 6078000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'noncurrent_liabilities': {'value': 2376000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': -836000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss': {'value': -21000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -21000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_parent': {'value': -836000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'cash_flow_statement': {'exchange_gains_losses': {'value': -6000000.0, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow_from_investing_activities': {'value': -130000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_financing_activities_continuing': {'value': 48000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_continuing': {'value': 4000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities': {'value': 48000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities_continuing': {'value': 86000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow': {'value': -2000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_operating_activities': {'value': 86000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities_continuing': {'value': -130000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}}, 'income_statement': {'diluted_earnings_per_share': {'value': -5.16, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'income_tax_expense_benefit': {'value': 14000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'basic_earnings_per_share': {'value': -5.16, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'operating_income_loss': {'value': -812000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'operating_expenses': {'value': 2124000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'income_tax_expense_benefit_deferred': {'value': 7000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'benefits_costs_expenses': {'value': 2659000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'net_income_loss': {'value': -815000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'cost_of_revenue': {'value': 546000000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'revenues': {'value': 1858000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -815000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'income_loss_from_continuing_operations_after_tax': {'value': -815000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'interest_expense_operating': {'value': 11000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'gross_profit': {'value': 1312000000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'income_tax_expense_benefit_current': {'value': 7000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Current', 'order': 2300}, 'costs_and_expenses': {'value': 2659000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'income_loss_from_continuing_operations_before_tax': {'value': -801000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_attributable_to_parent': {'value': -815000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}}}}, {'id': '0001660134:2023:Q3', 'start_date': '2022-08-01', 'end_date': '2022-10-31', 'filing_date': '2022-12-01', 'timeframe': 'quarterly', 'fiscal_period': 'Q3', 'fiscal_year': '2023', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-22-000056', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001660134-22-000056/files/okta-20221031_htm.xml', 'financials': {'income_statement': {'benefits_costs_expenses': {'value': 686211000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'diluted_earnings_per_share': {'value': -1.32, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'income_loss_from_continuing_operations_before_tax': {'value': -205169000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'interest_expense_operating': {'value': 2805000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'costs_and_expenses': {'value': 686211000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'operating_expenses': {'value': 549988000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'net_income_loss_attributable_to_parent': {'value': -208897000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'cost_of_revenue': {'value': 137653000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'operating_income_loss': {'value': -206599000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'gross_profit': {'value': 343389000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'revenues': {'value': 481042000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -208897000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'net_income_loss': {'value': -208897000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'basic_earnings_per_share': {'value': -1.32, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'income_loss_from_continuing_operations_after_tax': {'value': -208897000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'income_tax_expense_benefit': {'value': 3728000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss': {'value': -14878000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss': {'value': -223775000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': -223775000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'balance_sheet': {'noncurrent_assets': {'value': 6086799000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity': {'value': 5407612000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'current_assets': {'value': 3006937000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'other_than_fixed_noncurrent_assets': {'value': 6025915000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'liabilities_and_equity': {'value': 9093736000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'assets': {'value': 9093736000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'current_liabilities': {'value': 1309446000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'fixed_assets': {'value': 60884000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'liabilities': {'value': 3686124000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'noncurrent_liabilities': {'value': 2376678000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity_attributable_to_parent': {'value': 5407612000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}}, 'cash_flow_statement': {'net_cash_flow_from_operating_activities_continuing': {'value': 9980000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'exchange_gains_losses': {'value': -3675000.0, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow_from_investing_activities': {'value': 21489000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities': {'value': 9980000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_financing_activities_continuing': {'value': 5633000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': 21489000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_continuing': {'value': 37102000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities': {'value': 5633000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow': {'value': 33427000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}}}}, {'id': '0001660134:2023:Q2', 'start_date': '2022-05-01', 'end_date': '2022-07-31', 'filing_date': '2022-09-01', 'timeframe': 'quarterly', 'fiscal_period': 'Q2', 'fiscal_year': '2023', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-22-000042', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001660134-22-000042/files/okta-20220731_htm.xml', 'financials': {'balance_sheet': {'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'noncurrent_liabilities': {'value': 2384406000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity': {'value': 5453016000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'liabilities': {'value': 3620991000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'assets': {'value': 9074007000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'liabilities_and_equity': {'value': 9074007000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity_attributable_to_parent': {'value': 5453016000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'current_liabilities': {'value': 1236585000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'fixed_assets': {'value': 66958000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'other_than_fixed_noncurrent_assets': {'value': 6061547000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'current_assets': {'value': 2945502000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'noncurrent_assets': {'value': 6128505000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_parent': {'value': -215510000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss': {'value': -5038000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss': {'value': -215510000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}}, 'cash_flow_statement': {'net_cash_flow_continuing': {'value': 23131000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_investing_activities': {'value': 19630000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_financing_activities': {'value': 22550000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities_continuing': {'value': -19049000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities_continuing': {'value': 22550000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow': {'value': 21100000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_investing_activities_continuing': {'value': 19630000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities': {'value': -19049000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'exchange_gains_losses': {'value': -2031000.0, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}}, 'income_statement': {'operating_expenses': {'value': 522175000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'income_loss_from_continuing_operations_before_tax': {'value': -206256000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'interest_expense_operating': {'value': 2915000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_tax_expense_benefit': {'value': 4216000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'costs_and_expenses': {'value': 658063000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'basic_earnings_per_share': {'value': -1.34, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'revenues': {'value': 451807000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'gross_profit': {'value': 314113000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'cost_of_revenue': {'value': 137694000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'net_income_loss_attributable_to_parent': {'value': -210472000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'income_loss_from_continuing_operations_after_tax': {'value': -210472000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'operating_income_loss': {'value': -208062000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'net_income_loss': {'value': -210472000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -210472000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'benefits_costs_expenses': {'value': 658063000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'diluted_earnings_per_share': {'value': -1.34, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}}}}, {'id': '0001660134:2023:Q1', 'start_date': '2022-02-01', 'end_date': '2022-04-30', 'filing_date': '2022-06-03', 'timeframe': 'quarterly', 'fiscal_period': 'Q1', 'fiscal_year': '2023', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-22-000026', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001660134-22-000026/files/okta-20220430_htm.xml', 'financials': {'cash_flow_statement': {'net_cash_flow_from_investing_activities_continuing': {'value': -88342000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_continuing': {'value': -64129000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_operating_activities': {'value': 18831000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities': {'value': -88342000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'exchange_gains_losses': {'value': -4041000.0, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow': {'value': -68170000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities_continuing': {'value': 5382000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_operating_activities_continuing': {'value': 18831000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities': {'value': 5382000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}}, 'income_statement': {'income_loss_from_continuing_operations_before_tax': {'value': -240853000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'gross_profit': {'value': 283778000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'income_tax_expense_benefit': {'value': 1860000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'cost_of_revenue': {'value': 131165000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'net_income_loss': {'value': -242713000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'operating_income_loss': {'value': -239689000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'interest_expense_operating': {'value': 2868000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_loss_from_continuing_operations_after_tax': {'value': -242713000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'net_income_loss_attributable_to_parent': {'value': -242713000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'basic_earnings_per_share': {'value': -1.56, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'diluted_earnings_per_share': {'value': -1.56, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -242713000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'costs_and_expenses': {'value': 655796000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'benefits_costs_expenses': {'value': 655796000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'revenues': {'value': 414943000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'operating_expenses': {'value': 523467000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}}, 'comprehensive_income': {'other_comprehensive_income_loss': {'value': -24139000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'value': -266852000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': -266852000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}, 'balance_sheet': {'liabilities_and_equity': {'value': 9045681000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity': {'value': 5472694000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'current_liabilities': {'value': 1185275000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'assets': {'value': 9045681000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'equity_attributable_to_parent': {'value': 5472694000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'other_than_fixed_noncurrent_assets': {'value': 6080620000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'noncurrent_liabilities': {'value': 2387712000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'liabilities': {'value': 3572987000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'current_assets': {'value': 2898643000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'fixed_assets': {'value': 66418000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'noncurrent_assets': {'value': 6147038000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}}}}, {'id': '0001660134:2022:Q4', 'start_date': '2021-11-01', 'end_date': '2022-01-31', 'timeframe': 'quarterly', 'fiscal_period': 'Q4', 'fiscal_year': '2022', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'financials': {'income_statement': {'gross_profit': {'value': 263513000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'operating_expenses': {'value': 477939000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'income_loss_from_continuing_operations_before_tax': {'value': -235686000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'interest_expense_operating': {'value': 23406000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_loss_from_continuing_operations_after_tax': {'value': -241186000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -241186000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'costs_and_expenses': {'value': 618701000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'income_tax_expense_benefit': {'value': 5500000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'basic_earnings_per_share': {'value': -1.5600000000000005, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'operating_income_loss': {'value': -214426000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'diluted_earnings_per_share': {'value': -1.5600000000000005, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'revenues': {'value': 383015000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'net_income_loss': {'value': -241186000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'benefits_costs_expenses': {'value': 618701000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'net_income_loss_attributable_to_parent': {'value': -241186000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'cost_of_revenue': {'value': 119502000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': -253599000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss': {'value': -12413000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'value': -253599000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'balance_sheet': {'noncurrent_assets': {'value': 6165062000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'current_liabilities': {'value': 1242806000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'liabilities_and_equity': {'value': 9205695000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'equity_attributable_to_parent': {'value': 5921856000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'fixed_assets': {'value': 65488000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'liabilities': {'value': 3283839000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'noncurrent_liabilities': {'value': 2041033000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'current_assets': {'value': 3040633000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity': {'value': 5921856000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'assets': {'value': 9205695000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'other_than_fixed_noncurrent_assets': {'value': 6099574000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}}, 'cash_flow_statement': {'net_cash_flow_from_operating_activities': {'value': 13532000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'exchange_gains_losses': {'value': -1853000.0, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow_from_investing_activities': {'value': -156710000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow': {'value': -114412000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities': {'value': 30619000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_continuing': {'value': -112559000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities_continuing': {'value': 30619000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': -156710000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities_continuing': {'value': 13532000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}}}}, {'id': '0001660134:2022:FY', 'start_date': '2021-02-01', 'end_date': '2022-01-31', 'filing_date': '2022-03-07', 'timeframe': 'annual', 'fiscal_period': 'FY', 'fiscal_year': '2022', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-22-000010', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001660134-22-000010/files/okta-20220131_htm.xml', 'financials': {'balance_sheet': {'noncurrent_liabilities': {'value': 2041033000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'liabilities': {'value': 3283839000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'current_liabilities': {'value': 1242806000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'current_assets': {'value': 3040633000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity': {'value': 5921856000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'noncurrent_assets': {'value': 6165062000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'fixed_assets': {'value': 65488000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'equity_attributable_to_parent': {'value': 5921856000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'liabilities_and_equity': {'value': 9205695000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'assets': {'value': 9205695000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'other_than_fixed_noncurrent_assets': {'value': 6099574000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}}, 'cash_flow_statement': {'net_cash_flow_from_operating_activities': {'value': 104119000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities': {'value': -366812000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_financing_activities_continuing': {'value': 89066000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_continuing': {'value': -173627000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_investing_activities_continuing': {'value': -366812000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'exchange_gains_losses': {'value': -2347000.0, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow_from_operating_activities_continuing': {'value': 104119000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities': {'value': 89066000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow': {'value': -175974000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}}, 'income_statement': {'income_loss_from_continuing_operations_after_tax': {'value': -848411000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'income_tax_expense_benefit': {'value': -1285000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'benefits_costs_expenses': {'value': 2149897000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'diluted_earnings_per_share': {'value': -5.73, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'operating_income_loss': {'value': -767103000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'cost_of_revenue': {'value': 396405000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'interest_expense_operating': {'value': 92182000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'income_tax_expense_benefit_deferred': {'value': -6086000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'income_loss_from_continuing_operations_before_tax': {'value': -849696000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'operating_expenses': {'value': 1670899000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'costs_and_expenses': {'value': 2149897000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'net_income_loss': {'value': -848411000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -848411000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'revenues': {'value': 1300201000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'income_tax_expense_benefit_current': {'value': 4801000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Current', 'order': 2300}, 'net_income_loss_attributable_to_parent': {'value': -848411000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'gross_profit': {'value': 903796000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'basic_earnings_per_share': {'value': -5.73, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}}, 'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'value': -17399000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'other_comprehensive_income_loss': {'value': -17399000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'value': -865810000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': -865810000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}}}, {'id': '0001660134:2022:Q3', 'start_date': '2021-08-01', 'end_date': '2021-10-31', 'filing_date': '2021-12-02', 'timeframe': 'quarterly', 'fiscal_period': 'Q3', 'fiscal_year': '2022', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-21-000026', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001660134-21-000026/files/okta-20211031_htm.xml', 'financials': {'comprehensive_income': {'comprehensive_income_loss': {'value': -225282000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss': {'value': -3971000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss_attributable_to_parent': {'value': -225282000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'balance_sheet': {'fixed_assets': {'value': 60751000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'liabilities_and_equity': {'value': 8996973000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'noncurrent_liabilities': {'value': 2024252000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'liabilities': {'value': 3012418000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'noncurrent_assets': {'value': 6144105000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity_attributable_to_parent': {'value': 5984555000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'other_than_fixed_noncurrent_assets': {'value': 6083354000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'equity': {'value': 5984555000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'assets': {'value': 8996973000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'current_assets': {'value': 2852868000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'current_liabilities': {'value': 988166000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}}, 'income_statement': {'gross_profit': {'value': 241006000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'benefits_costs_expenses': {'value': 571324000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'diluted_earnings_per_share': {'value': -1.44, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'income_tax_expense_benefit': {'value': 667000, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'net_income_loss': {'value': -221311000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'income_loss_from_continuing_operations_after_tax': {'value': -221311000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'operating_expenses': {'value': 439562000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'basic_earnings_per_share': {'value': -1.44, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -221311000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'costs_and_expenses': {'value': 571324000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'income_loss_from_continuing_operations_before_tax': {'value': -220644000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'operating_income_loss': {'value': -198556000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss_attributable_to_parent': {'value': -221311000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'revenues': {'value': 350680000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'cost_of_revenue': {'value': 109674000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'interest_expense_operating': {'value': 23144000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}}, 'cash_flow_statement': {'net_cash_flow_from_investing_activities': {'value': 101459000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow': {'value': 147106000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_investing_activities_continuing': {'value': 101459000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_continuing': {'value': 147793000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities_continuing': {'value': 9214000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_operating_activities': {'value': 37120000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'exchange_gains_losses': {'value': -687000, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow_from_operating_activities_continuing': {'value': 37120000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities': {'value': 9214000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}}}}, {'id': '0001660134:2022:Q2', 'start_date': '2021-05-01', 'end_date': '2021-07-31', 'filing_date': '2021-09-02', 'timeframe': 'quarterly', 'fiscal_period': 'Q2', 'fiscal_year': '2022', 'cik': '0001660134', 'sic': '7372', 'tickers': ['OKTA'], 'company_name': 'Okta, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001660134-21-000020', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001660134-21-000020/files/okta-20210731_htm.xml', 'financials': {'balance_sheet': {'noncurrent_assets': {'value': 6054937000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'fixed_assets': {'value': 61858000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'noncurrent_liabilities': {'value': 1977371000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'other_than_fixed_noncurrent_assets': {'value': 5993079000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'equity_attributable_to_parent': {'value': 6042190000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'liabilities_and_equity': {'value': 8932095000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'liabilities': {'value': 2889905000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'current_assets': {'value': 2877158000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'current_liabilities': {'value': 912534000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'equity': {'value': 6042190000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'assets': {'value': 8932095000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}}, 'income_statement': {'operating_expenses': {'value': 477834000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'net_income_loss': {'value': -276682000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -276682000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'operating_income_loss': {'value': -263440000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss_attributable_to_parent': {'value': -276682000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'interest_expense_operating': {'value': 22872000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'benefits_costs_expenses': {'value': 599644000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'income_loss_from_continuing_operations_after_tax': {'value': -276682000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'gross_profit': {'value': 214394000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'revenues': {'value': 315500000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'diluted_earnings_per_share': {'value': -1.83, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'income_tax_expense_benefit': {'value': -7462000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'income_loss_from_continuing_operations_before_tax': {'value': -284144000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'basic_earnings_per_share': {'value': -1.83, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'costs_and_expenses': {'value': 599644000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'cost_of_revenue': {'value': 101106000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}}, 'cash_flow_statement': {'net_cash_flow': {'value': -433474000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'exchange_gains_losses': {'value': -454000, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow_from_investing_activities_continuing': {'value': -463466000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_financing_activities_continuing': {'value': 33054000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_financing_activities': {'value': 33054000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities_continuing': {'value': -2608000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_continuing': {'value': -433020000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_investing_activities': {'value': -463466000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities': {'value': -2608000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_parent': {'value': -277917000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss': {'value': -1235000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss': {'value': -277917000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}}}], 'status': 'OK', 'request_id': 'bfe9d0473817b63749e9910fffb4fa68', 'next_url': 'https://api.polygon.io/vX/reference/financials?cursor=YXA9MDAwMTY2MDEzNCUzQTIwMjIlM0FRMiZhcz0mbGltaXQ9MTAmcGVyaW9kX29mX3JlcG9ydF9kYXRlLmx0ZT0yMDIxLTA3LTMxJnNvcnQ9cGVyaW9kX29mX3JlcG9ydF9kYXRlJnRpY2tlcj1PS1RB'}\n", - "output_value": " 0 ... 3\n0 Okta, Inc. Class A Common Stock ... 7.312640133003229\n\n[1 rows x 4 columns]", - "cells_accessed": [[7, 12]], - "array_output": [ - ["Okta, Inc. Class A Common Stock", "1858000000.0", "13586885367.119999", "7.312640133003229"] - ], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 12)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nprint(stock_financials_json)\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - }, - "dependent_cells": [[7, 12]] - }, - { - "x": 8, - "y": 13, - "type": "PYTHON", - "value": "Oracle Corp", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 13)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nprint(stock_financials_json)\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:55:01.055Z", - "python_output": "{'results': [{'financials': {'balance_sheet': {'noncurrent_assets': {'label': 'Noncurrent Assets', 'value': 76969000000.0, 'unit': 'USD', 'order': 300}, 'fixed_assets': {'label': 'Fixed Assets', 'value': 8609000000.0, 'unit': 'USD', 'order': 400}, 'current_liabilities': {'label': 'Current Liabilities', 'value': 20833000000.0, 'unit': 'USD', 'order': 700}, 'assets': {'label': 'Assets', 'value': 108644000000.0, 'unit': 'USD', 'order': 100}, 'noncurrent_liabilities': {'label': 'Noncurrent Liabilities', 'value': 96022000000.0, 'unit': 'USD', 'order': 800}, 'equity_attributable_to_noncontrolling_interest': {'label': 'Equity Attributable To Noncontrolling Interest', 'value': 485000000.0, 'unit': 'USD', 'order': 1500}, 'equity_attributable_to_parent': {'label': 'Equity Attributable To Parent', 'value': -8696000000.0, 'unit': 'USD', 'order': 1600}, 'commitments_and_contingencies': {'label': 'Commitments and Contingencies', 'value': 0, 'unit': 'USD', 'order': 900}, 'other_than_fixed_noncurrent_assets': {'label': 'Other Than Fixed Noncurrent Assets', 'value': 76969000000.0, 'unit': 'USD', 'order': 500}, 'current_assets': {'label': 'Current Assets', 'value': 31675000000.0, 'unit': 'USD', 'order': 200}, 'liabilities_and_equity': {'label': 'Liabilities And Equity', 'value': 108644000000.0, 'unit': 'USD', 'order': 1900}, 'equity': {'label': 'Equity', 'value': -8211000000.0, 'unit': 'USD', 'order': 1400}, 'liabilities': {'label': 'Liabilities', 'value': 116855000000.0, 'unit': 'USD', 'order': 600}}, 'cash_flow_statement': {}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 200}, 'other_comprehensive_income_loss': {'label': 'Other Comprehensive Income/Loss', 'value': 2257000000.0, 'unit': 'USD', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'label': 'Comprehensive Income/Loss Attributable To Parent', 'value': 2257000000.0, 'unit': 'USD', 'order': 300}, 'other_comprehensive_income_loss_attributable_to_parent': {'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'value': -62000000.0, 'unit': 'USD', 'order': 600}, 'comprehensive_income_loss': {'label': 'Comprehensive Income/Loss', 'value': 2257000000.0, 'unit': 'USD', 'order': 100}}, 'income_statement': {'preferred_stock_dividends_and_other_adjustments': {'label': 'Preferred Stock Dividends And Other Adjustments', 'value': 0, 'unit': 'USD', 'order': 3900}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'value': 0, 'unit': 'USD', 'order': 3800}, 'operating_income_loss': {'label': 'Operating Income/Loss', 'value': 3822000000.0, 'unit': 'USD', 'order': 1100}, 'income_loss_from_continuing_operations_after_tax': {'label': 'Income/Loss From Continuing Operations After Tax', 'value': 2319000000.0, 'unit': 'USD', 'order': 1400}, 'basic_earnings_per_share': {'label': 'Basic Earnings Per Share', 'value': 0.87, 'unit': 'USD / shares', 'order': 4200}, 'net_income_loss': {'label': 'Net Income/Loss', 'value': 2319000000.0, 'unit': 'USD', 'order': 3200}, 'costs_and_expenses': {'label': 'Costs And Expenses', 'value': 6691000000.0, 'unit': 'USD', 'order': 600}, 'diluted_earnings_per_share': {'label': 'Diluted Earnings Per Share', 'value': 0.84, 'unit': 'USD / shares', 'order': 4300}, 'operating_expenses': {'label': 'Operating Expenses', 'value': -3822000000.0, 'unit': 'USD', 'order': 1000}, 'interest_expense_operating': {'label': 'Interest Expense, Operating', 'value': 667000000.0, 'unit': 'USD', 'order': 2700}, 'net_income_loss_available_to_common_stockholders_basic': {'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'value': 2319000000.0, 'unit': 'USD', 'order': 3700}, 'net_income_loss_attributable_to_noncontrolling_interest': {'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 3300}, 'income_loss_from_continuing_operations_before_tax': {'label': 'Income/Loss From Continuing Operations Before Tax', 'value': 3822000000.0, 'unit': 'USD', 'order': 1500}, 'benefits_costs_expenses': {'label': 'Benefits Costs and Expenses', 'value': 6691000000.0, 'unit': 'USD', 'order': 200}, 'revenues': {'label': 'Revenues', 'value': 10513000000.0, 'unit': 'USD', 'order': 100}, 'net_income_loss_attributable_to_parent': {'label': 'Net Income/Loss Attributable To Parent', 'value': 2319000000.0, 'unit': 'USD', 'order': 3500}, 'income_tax_expense_benefit': {'label': 'Income Tax Expense/Benefit', 'value': 521000000.0, 'unit': 'USD', 'order': 2200}}}, 'start_date': '2021-12-01', 'end_date': '2022-02-28', 'filing_date': '2022-03-11', 'cik': '0001341439', 'company_name': 'Oracle Corporation', 'fiscal_period': 'Q3', 'fiscal_year': '2022', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-009859', 'source_filing_file_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-009859/files/orcl-10q_20220228_htm.xml'}], 'status': 'OK', 'request_id': '5fe1c2509e0933661af166d001f1b65a', 'count': 1, 'next_url': 'https://api.polygon.io/vX/reference/financials?cursor=YXA9MjAyMjAyMjgmYXM9MDAwMTU2NDU5MC0yMi0wMDk4NTkmZW50aXRpZXMuY29tcGFueV9kYXRhLnRpY2tlcj1PUkNMJmhhc194YnJsPXRydWUmbGltaXQ9MSZzb3J0PXBlcmlvZF9vZl9yZXBvcnRfZGF0ZSZ0eXBlPTEwLVE'}\n", - "array_cells": [ - [8, 13], - [9, 13], - [10, 13], - [11, 13] - ], - "evaluation_result": { - "success": true, - "std_out": "{'results': [{'id': '0001341439:TTM', 'start_date': '2022-03-01', 'end_date': '2023-02-28', 'timeframe': 'ttm', 'fiscal_period': 'TTM', 'fiscal_year': '', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'financials': {'income_statement': {'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'costs_and_expenses': {'value': 27165000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'operating_income_loss': {'value': 13455000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'diluted_earnings_per_share': {'value': 3.0300000000000002, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'benefits_costs_expenses': {'value': 27165000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'income_loss_from_continuing_operations_before_tax': {'value': 51393000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 8373000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'basic_earnings_per_share': {'value': 3.12, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'revenues': {'value': 78558000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'operating_expenses': {'value': 34503000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 184000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'income_tax_expense_benefit_deferred': {'value': -1416000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'income_loss_from_continuing_operations_after_tax': {'value': 47624000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'net_income_loss_attributable_to_parent': {'value': 8373000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'income_tax_expense_benefit': {'value': 1268000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'interest_expense_operating': {'value': 3254000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'net_income_loss': {'value': 8557000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}}, 'balance_sheet': {'assets': {'value': 131620000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'equity': {'value': -1912000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'other_than_fixed_noncurrent_assets': {'value': 112924000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'liabilities_and_equity': {'value': 131620000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity_attributable_to_noncontrolling_interest': {'value': 509000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'fixed_assets': {'value': 16345000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'noncurrent_assets': {'value': 112924000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'liabilities': {'value': 133532000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'current_assets': {'value': 18696000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'current_liabilities': {'value': 22880000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'equity_attributable_to_parent': {'value': -2421000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'noncurrent_liabilities': {'value': 110652000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}}, 'comprehensive_income': {'comprehensive_income_loss': {'value': 8357000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss': {'value': 1590000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'value': 8357000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -16000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}}, 'cash_flow_statement': {'net_cash_flow': {'value': -14206000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities': {'value': 6324000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities': {'value': 15503000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_continuing': {'value': -14206000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_operating_activities_continuing': {'value': 15503000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities': {'value': -36033000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_financing_activities_continuing': {'value': 6324000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': -36033000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}}}}, {'id': '0001341439:2023:Q3', 'start_date': '2022-12-01', 'end_date': '2023-02-28', 'filing_date': '2023-03-10', 'timeframe': 'quarterly', 'fiscal_period': 'Q3', 'fiscal_year': '2023', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-23-003413', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-23-003413/files/orcl-10q_20230228_htm.xml', 'financials': {'comprehensive_income': {'other_comprehensive_income_loss': {'value': 1979000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': 1979000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': 83000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_parent': {'value': 1979000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'income_statement': {'operating_expenses': {'value': 9138000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'benefits_costs_expenses': {'value': 9138000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'net_income_loss': {'value': 1896000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'income_tax_expense_benefit_deferred': {'value': -401000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'income_tax_expense_benefit': {'value': 322000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'net_income_loss_attributable_to_parent': {'value': 1896000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'interest_expense_operating': {'value': 908000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 1896000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'income_loss_from_continuing_operations_after_tax': {'value': 1896000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'operating_income_loss': {'value': 3260000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'diluted_earnings_per_share': {'value': 0.68, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'income_loss_from_continuing_operations_before_tax': {'value': 3260000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'basic_earnings_per_share': {'value': 0.7, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'revenues': {'value': 12398000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'costs_and_expenses': {'value': 9138000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}}, 'balance_sheet': {'noncurrent_liabilities': {'value': 110652000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'liabilities_and_equity': {'value': 131620000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity': {'value': -1912000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'assets': {'value': 131620000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'liabilities': {'value': 133532000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'current_assets': {'value': 18696000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity_attributable_to_parent': {'value': -2421000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'noncurrent_assets': {'value': 112924000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity_attributable_to_noncontrolling_interest': {'value': 509000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'current_liabilities': {'value': 22880000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'other_than_fixed_noncurrent_assets': {'value': 112924000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'fixed_assets': {'value': 16345000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}}, 'cash_flow_statement': {'net_cash_flow_from_financing_activities_continuing': {'value': -105000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_operating_activities': {'value': 4275000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_operating_activities_continuing': {'value': 4275000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities_continuing': {'value': -2778000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_investing_activities': {'value': -2778000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_continuing': {'value': 1392000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow': {'value': 1392000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities': {'value': -105000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}}}}, {'id': '0001341439:2023:Q2', 'start_date': '2022-09-01', 'end_date': '2022-11-30', 'filing_date': '2022-12-13', 'timeframe': 'quarterly', 'fiscal_period': 'Q2', 'fiscal_year': '2023', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-039278', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-22-039278/files/orcl-10q_20221130_htm.xml', 'financials': {'cash_flow_statement': {'net_cash_flow_continuing': {'value': -3664000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities': {'value': -1855000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow': {'value': -3664000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_investing_activities_continuing': {'value': -2658000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities': {'value': 849000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_financing_activities_continuing': {'value': -1855000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_operating_activities_continuing': {'value': 849000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities': {'value': -2658000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}}, 'income_statement': {'income_tax_expense_benefit_deferred': {'value': -508000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'interest_expense_operating': {'value': 856000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'operating_income_loss': {'value': 3071000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'income_loss_from_continuing_operations_before_tax': {'value': 3071000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'income_loss_from_continuing_operations_after_tax': {'value': 1741000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'revenues': {'value': 12275000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'income_tax_expense_benefit': {'value': 403000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'basic_earnings_per_share': {'value': 0.65, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss': {'value': 1741000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'diluted_earnings_per_share': {'value': 0.63, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss_attributable_to_parent': {'value': 1741000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'operating_expenses': {'value': 9204000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'benefits_costs_expenses': {'value': 9204000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 1741000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'costs_and_expenses': {'value': 9204000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}}, 'balance_sheet': {'noncurrent_liabilities': {'value': 105139000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'noncurrent_assets': {'value': 110908000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'other_than_fixed_noncurrent_assets': {'value': 110908000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'assets': {'value': 128469000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'equity_attributable_to_parent': {'value': -4246000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'liabilities': {'value': 132245000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'liabilities_and_equity': {'value': 128469000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity': {'value': -3776000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'fixed_assets': {'value': 14351000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_noncontrolling_interest': {'value': 470000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'current_liabilities': {'value': 27106000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'current_assets': {'value': 17561000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}}, 'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'value': 188000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_parent': {'value': 1929000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss': {'value': 1929000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': 1929000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}}}, {'id': '0001341439:2023:Q1', 'start_date': '2022-06-01', 'end_date': '2022-08-31', 'filing_date': '2022-09-13', 'timeframe': 'quarterly', 'fiscal_period': 'Q1', 'fiscal_year': '2023', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-031545', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-22-031545/files/orcl-10q_20220831_htm.xml', 'financials': {'comprehensive_income': {'comprehensive_income_loss': {'value': 1276000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -272000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'other_comprehensive_income_loss': {'value': 1276000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss_attributable_to_parent': {'value': 1276000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'balance_sheet': {'equity': {'value': -5449000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'equity_attributable_to_parent': {'value': -5875000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'fixed_assets': {'value': 12280000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_noncontrolling_interest': {'value': 426000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'noncurrent_assets': {'value': 109305000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'liabilities': {'value': 135758000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'assets': {'value': 130309000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'current_assets': {'value': 21004000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'current_liabilities': {'value': 34819000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'liabilities_and_equity': {'value': 130309000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'noncurrent_liabilities': {'value': 100939000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'other_than_fixed_noncurrent_assets': {'value': 109305000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}}, 'cash_flow_statement': {'net_cash_flow_continuing': {'value': -10732000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_operating_activities_continuing': {'value': 6394000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities': {'value': 12310000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_financing_activities_continuing': {'value': 12310000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': -29436000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_investing_activities': {'value': -29436000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities': {'value': 6394000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow': {'value': -10732000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}}, 'income_statement': {'benefits_costs_expenses': {'value': 8822000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'basic_earnings_per_share': {'value': 0.58, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 1548000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'income_loss_from_continuing_operations_after_tax': {'value': 1548000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'diluted_earnings_per_share': {'value': 0.56, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'costs_and_expenses': {'value': 8822000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'interest_expense_operating': {'value': 787000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'net_income_loss': {'value': 1548000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_attributable_to_parent': {'value': 1548000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'income_tax_expense_benefit': {'value': 108000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'income_loss_from_continuing_operations_before_tax': {'value': 2623000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'operating_expenses': {'value': 8822000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'revenues': {'value': 11445000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'operating_income_loss': {'value': 2623000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'income_tax_expense_benefit_deferred': {'value': -344000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}}}}, {'id': '0001341439:2022:Q4', 'start_date': '2022-03-01', 'end_date': '2022-05-31', 'timeframe': 'quarterly', 'fiscal_period': 'Q4', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'financials': {'income_statement': {'operating_income_loss': {'value': 4502000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'costs_and_expenses': {'value': 0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'income_loss_from_continuing_operations_before_tax': {'value': 42440000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'net_income_loss': {'value': 3373000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 3189000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'basic_earnings_per_share': {'value': 1.1900000000000002, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss_attributable_to_parent': {'value': 3189000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'benefits_costs_expenses': {'value': 0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'revenues': {'value': 42440000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'income_tax_expense_benefit': {'value': 435000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 184000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'income_loss_from_continuing_operations_after_tax': {'value': 42440000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'income_tax_expense_benefit_deferred': {'value': -163000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'interest_expense_operating': {'value': 704000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'operating_expenses': {'value': 7338000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'diluted_earnings_per_share': {'value': 1.1500000000000001, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}}, 'cash_flow_statement': {'net_cash_flow_from_financing_activities': {'value': -4026000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities': {'value': 3985000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_operating_activities_continuing': {'value': 3985000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities_continuing': {'value': -1161000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow': {'value': -1202000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_continuing': {'value': -1202000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities_continuing': {'value': -4026000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities': {'value': -1161000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}}, 'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'value': -14000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'other_comprehensive_income_loss': {'value': -3592000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss_attributable_to_parent': {'value': 3175000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss': {'value': 3175000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}, 'balance_sheet': {'liabilities': {'value': 115065000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'noncurrent_assets': {'value': 77664000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'current_liabilities': {'value': 19511000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'equity_attributable_to_parent': {'value': -6220000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'fixed_assets': {'value': 9716000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity': {'value': -5768000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'equity_attributable_to_noncontrolling_interest': {'value': 452000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'noncurrent_liabilities': {'value': 95554000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'other_than_fixed_noncurrent_assets': {'value': 77664000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'liabilities_and_equity': {'value': 109297000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'assets': {'value': 109297000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'current_assets': {'value': 31633000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}}}}, {'id': '0001341439:2022:FY', 'start_date': '2021-06-01', 'end_date': '2022-05-31', 'filing_date': '2022-06-21', 'timeframe': 'annual', 'fiscal_period': 'FY', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-023675', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-22-023675/files/orcl-10k_20220531_htm.xml', 'financials': {'balance_sheet': {'equity': {'value': -5768000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'fixed_assets': {'value': 9716000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'assets': {'value': 109297000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'current_assets': {'value': 31633000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'noncurrent_liabilities': {'value': 95554000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'other_than_fixed_noncurrent_assets': {'value': 77664000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'current_liabilities': {'value': 19511000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'liabilities': {'value': 115065000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'equity_attributable_to_noncontrolling_interest': {'value': 452000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'liabilities_and_equity': {'value': 109297000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity_attributable_to_parent': {'value': -6220000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'noncurrent_assets': {'value': 77664000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}}, 'income_statement': {'net_income_loss_attributable_to_parent': {'value': 6717000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'income_tax_expense_benefit_current': {'value': 2078000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Current', 'order': 2300}, 'interest_expense_operating': {'value': 2755000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'revenues': {'value': 42440000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'basic_earnings_per_share': {'value': 2.49, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'benefits_costs_expenses': {'value': 31514000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'costs_and_expenses': {'value': 31514000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'net_income_loss': {'value': 6901000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'income_loss_from_continuing_operations_before_tax': {'value': 10926000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 6717000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'income_tax_expense_benefit': {'value': 932000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'diluted_earnings_per_share': {'value': 2.41, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'income_tax_expense_benefit_deferred': {'value': -1146000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'operating_income_loss': {'value': 10926000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'income_loss_from_continuing_operations_after_tax': {'value': 6901000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 184000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'operating_expenses': {'value': 31514000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}}, 'cash_flow_statement': {'net_cash_flow_from_operating_activities_continuing': {'value': 9539000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities': {'value': -29126000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_financing_activities_continuing': {'value': -29126000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': 11220000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_investing_activities': {'value': 11220000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities': {'value': 9539000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow': {'value': -8367000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_continuing': {'value': -8367000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}}, 'comprehensive_income': {'other_comprehensive_income_loss': {'value': -567000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'value': 6200000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -517000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss': {'value': 6200000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}}}}, {'id': '0001341439:2022:Q3', 'start_date': '2021-12-01', 'end_date': '2022-02-28', 'filing_date': '2022-03-11', 'timeframe': 'quarterly', 'fiscal_period': 'Q3', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-009859', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-22-009859/files/orcl-10q_20220228_htm.xml', 'financials': {'income_statement': {'income_tax_expense_benefit': {'value': 521000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'income_tax_expense_benefit_deferred': {'value': -163000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'costs_and_expenses': {'value': 6691000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'income_loss_from_continuing_operations_after_tax': {'value': 2319000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 2319000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'net_income_loss': {'value': 2319000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'basic_earnings_per_share': {'value': 0.87, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'benefits_costs_expenses': {'value': 6691000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'interest_expense_operating': {'value': 667000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'net_income_loss_attributable_to_parent': {'value': 2319000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'operating_income_loss': {'value': 3822000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'diluted_earnings_per_share': {'value': 0.84, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'operating_expenses': {'value': 6691000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'revenues': {'value': 10513000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'income_loss_from_continuing_operations_before_tax': {'value': 3822000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}}, 'balance_sheet': {'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'equity_attributable_to_parent': {'value': -8696000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'noncurrent_assets': {'value': 76969000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity': {'value': -8211000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'liabilities_and_equity': {'value': 108644000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'assets': {'value': 108644000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'current_assets': {'value': 31675000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'current_liabilities': {'value': 20833000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'other_than_fixed_noncurrent_assets': {'value': 76969000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'fixed_assets': {'value': 8609000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'noncurrent_liabilities': {'value': 96022000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity_attributable_to_noncontrolling_interest': {'value': 485000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'liabilities': {'value': 116855000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}}, 'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'value': -62000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss': {'value': 2257000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': 2257000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss': {'value': 2257000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}}, 'cash_flow_statement': {'net_cash_flow_from_investing_activities': {'value': 2432000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_continuing': {'value': 4698000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow': {'value': 4698000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_operating_activities_continuing': {'value': 3845000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities_continuing': {'value': -1579000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': 2432000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_financing_activities': {'value': -1579000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities': {'value': 3845000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}}}}, {'id': '0001341439:2022:Q2', 'start_date': '2021-09-01', 'end_date': '2021-11-30', 'filing_date': '2021-12-10', 'timeframe': 'quarterly', 'fiscal_period': 'Q2', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-21-060022', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-21-060022/files/orcl-10q_20211130_htm.xml', 'financials': {'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'value': -220000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'other_comprehensive_income_loss': {'value': -1467000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss_attributable_to_parent': {'value': -1467000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss': {'value': -1467000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}, 'income_statement': {'benefits_costs_expenses': {'value': 11184000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'basic_earnings_per_share': {'value': -0.46, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'income_tax_expense_benefit': {'value': -249000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'income_loss_from_continuing_operations_after_tax': {'value': -1247000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'operating_income_loss': {'value': -824000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss_attributable_to_parent': {'value': -1247000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'net_income_loss': {'value': -1247000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_loss_from_continuing_operations_before_tax': {'value': -824000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'operating_expenses': {'value': 11184000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'diluted_earnings_per_share': {'value': -0.46, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'income_tax_expense_benefit_deferred': {'value': -805000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -1247000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'revenues': {'value': 10360000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'costs_and_expenses': {'value': 11184000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'interest_expense_operating': {'value': 679000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}}, 'cash_flow_statement': {'net_cash_flow': {'value': -5005000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_investing_activities': {'value': 10730000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities': {'value': -3682000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_financing_activities': {'value': -12053000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_continuing': {'value': -5005000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_operating_activities_continuing': {'value': -3682000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities_continuing': {'value': 10730000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_financing_activities_continuing': {'value': -12053000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}}, 'balance_sheet': {'assets': {'value': 106897000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'liabilities_and_equity': {'value': 106897000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'current_liabilities': {'value': 18881000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'other_than_fixed_noncurrent_assets': {'value': 75819000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'equity_attributable_to_parent': {'value': -10101000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'noncurrent_assets': {'value': 75819000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'current_assets': {'value': 31078000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity': {'value': -9658000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'liabilities': {'value': 116555000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'fixed_assets': {'value': 8029000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'noncurrent_liabilities': {'value': 97674000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity_attributable_to_noncontrolling_interest': {'value': 443000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}}}}, {'id': '0001341439:2022:Q1', 'start_date': '2021-06-01', 'end_date': '2021-08-31', 'filing_date': '2021-09-13', 'timeframe': 'quarterly', 'fiscal_period': 'Q1', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-21-047772', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-21-047772/files/orcl-10q_20210831_htm.xml', 'financials': {'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'value': -221000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss': {'value': 2236000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss': {'value': 2236000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': 2236000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'balance_sheet': {'fixed_assets': {'value': 7610000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'liabilities': {'value': 124054000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'liabilities_and_equity': {'value': 122924000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'current_assets': {'value': 47117000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity_attributable_to_parent': {'value': -1541000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'current_liabilities': {'value': 23071000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'equity': {'value': -1130000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'equity_attributable_to_noncontrolling_interest': {'value': 411000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'other_than_fixed_noncurrent_assets': {'value': 75807000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'assets': {'value': 122924000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_assets': {'value': 75807000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'noncurrent_liabilities': {'value': 100983000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}}, 'income_statement': {'benefits_costs_expenses': {'value': 6301000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'costs_and_expenses': {'value': 6301000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'net_income_loss': {'value': 2457000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'revenues': {'value': 9728000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'income_tax_expense_benefit': {'value': 224000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'interest_expense_operating': {'value': 705000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'diluted_earnings_per_share': {'value': 0.86, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'operating_expenses': {'value': 6301000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'operating_income_loss': {'value': 3427000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'income_loss_from_continuing_operations_before_tax': {'value': 3427000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'income_loss_from_continuing_operations_after_tax': {'value': 2457000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'income_tax_expense_benefit_deferred': {'value': -15000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'basic_earnings_per_share': {'value': 0.89, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'net_income_loss_attributable_to_parent': {'value': 2457000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 2457000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}}, 'cash_flow_statement': {'net_cash_flow_from_financing_activities': {'value': -11468000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities': {'value': 5391000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities': {'value': -781000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities_continuing': {'value': 5391000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities_continuing': {'value': -781000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow': {'value': -6858000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_continuing': {'value': -6858000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities_continuing': {'value': -11468000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}}}}, {'id': '0001341439:2021:Q4', 'start_date': '2021-03-01', 'end_date': '2021-05-31', 'timeframe': 'quarterly', 'fiscal_period': 'Q4', 'fiscal_year': '2021', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'financials': {'income_statement': {'net_income_loss_attributable_to_parent': {'value': 4032000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'income_tax_expense_benefit': {'value': 124000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'basic_earnings_per_share': {'value': 1.4100000000000001, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'operating_expenses': {'value': 6686000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'income_loss_from_continuing_operations_before_tax': {'value': 40479000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 4032000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'net_income_loss': {'value': 4212000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'diluted_earnings_per_share': {'value': 1.3599999999999999, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'costs_and_expenses': {'value': 0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'income_tax_expense_benefit_deferred': {'value': 50000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 180000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'income_loss_from_continuing_operations_after_tax': {'value': 40479000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'operating_income_loss': {'value': 4541000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'revenues': {'value': 40479000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'interest_expense_operating': {'value': 697000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'benefits_costs_expenses': {'value': 0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}}, 'comprehensive_income': {'other_comprehensive_income_loss': {'value': -9732000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss': {'value': 4012000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': 4012000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -20000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}}, 'balance_sheet': {'noncurrent_assets': {'value': 75540000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity': {'value': 5952000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'equity_attributable_to_noncontrolling_interest': {'value': 714000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'assets': {'value': 131107000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'liabilities_and_equity': {'value': 131107000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'current_assets': {'value': 55567000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'current_liabilities': {'value': 24164000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'liabilities': {'value': 125155000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'noncurrent_liabilities': {'value': 100991000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity_attributable_to_parent': {'value': 5238000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'fixed_assets': {'value': 7049000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'other_than_fixed_noncurrent_assets': {'value': 75540000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}}, 'cash_flow_statement': {'net_cash_flow_from_investing_activities': {'value': -3911000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_investing_activities_continuing': {'value': -3911000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities_continuing': {'value': 4842000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow': {'value': 7729000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities_continuing': {'value': 6798000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_operating_activities': {'value': 4842000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_continuing': {'value': 7729000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities': {'value': 6798000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}}}}], 'status': 'OK', 'request_id': '52a994a69007495ccbd91044d82e8da7', 'next_url': 'https://api.polygon.io/vX/reference/financials?cursor=YXA9MDAwMTM0MTQzOSUzQTIwMjElM0FRNCZhcz0mbGltaXQ9MTAmcGVyaW9kX29mX3JlcG9ydF9kYXRlLmx0ZT0yMDIxLTA1LTMxJnNvcnQ9cGVyaW9kX29mX3JlcG9ydF9kYXRlJnRpY2tlcj1PUkNM'}\n", - "output_value": " 0 1 2 3\n0 Oracle Corp 78558000000.0 234774781919.99997 2.9885534499350794", - "cells_accessed": [[7, 13]], - "array_output": [["Oracle Corp", "78558000000.0", "234774781919.99997", "2.9885534499350794"]], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 13)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nprint(stock_financials_json)\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - } - }, - { - "x": 8, - "y": 14, - "type": "PYTHON", - "value": "DigitalOcean Holdings, Inc.", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 14)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nprint(stock_financials_json)\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:55:05.226Z", - "python_output": "{'results': [{'financials': {'comprehensive_income': {'comprehensive_income_loss': {'label': 'Comprehensive Income/Loss', 'value': -20049000.0, 'unit': 'USD', 'order': 100}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 200}, 'other_comprehensive_income_loss': {'label': 'Other Comprehensive Income/Loss', 'value': -20049000.0, 'unit': 'USD', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'label': 'Comprehensive Income/Loss Attributable To Parent', 'value': -20049000.0, 'unit': 'USD', 'order': 300}, 'other_comprehensive_income_loss_attributable_to_parent': {'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'value': -1926000.0, 'unit': 'USD', 'order': 600}}, 'income_statement': {'gross_profit': {'label': 'Gross Profit', 'value': 80570000.0, 'unit': 'USD', 'order': 800}, 'net_income_loss': {'label': 'Net Income/Loss', 'value': -18123000.0, 'unit': 'USD', 'order': 3200}, 'operating_expenses': {'label': 'Operating Expenses', 'value': 93709000.0, 'unit': 'USD', 'order': 1000}, 'net_income_loss_available_to_common_stockholders_basic': {'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'value': -18123000.0, 'unit': 'USD', 'order': 3700}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'value': 0, 'unit': 'USD', 'order': 3800}, 'diluted_earnings_per_share': {'label': 'Diluted Earnings Per Share', 'value': -0.17, 'unit': 'USD / shares', 'order': 4300}, 'nonoperating_income_loss': {'label': 'Nonoperating Income/Loss', 'value': -1646000.0, 'unit': 'USD', 'order': 900}, 'operating_income_loss': {'label': 'Operating Income/Loss', 'value': -13139000.0, 'unit': 'USD', 'order': 1100}, 'income_tax_expense_benefit': {'label': 'Income Tax Expense/Benefit', 'value': 3338000.0, 'unit': 'USD', 'order': 2200}, 'income_loss_from_continuing_operations_after_tax': {'label': 'Income/Loss From Continuing Operations After Tax', 'value': -18123000.0, 'unit': 'USD', 'order': 1400}, 'preferred_stock_dividends_and_other_adjustments': {'label': 'Preferred Stock Dividends And Other Adjustments', 'value': 0, 'unit': 'USD', 'order': 3900}, 'net_income_loss_attributable_to_noncontrolling_interest': {'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 3300}, 'costs_and_expenses': {'label': 'Costs And Expenses', 'value': 142112000.0, 'unit': 'USD', 'order': 600}, 'interest_expense_operating': {'label': 'Interest Expense, Operating', 'value': 2059000.0, 'unit': 'USD', 'order': 2700}, 'income_loss_from_continuing_operations_before_tax': {'label': 'Income/Loss From Continuing Operations Before Tax', 'value': -14785000.0, 'unit': 'USD', 'order': 1500}, 'benefits_costs_expenses': {'label': 'Benefits Costs and Expenses', 'value': 142112000.0, 'unit': 'USD', 'order': 200}, 'cost_of_revenue': {'label': 'Cost Of Revenue', 'value': 46757000.0, 'unit': 'USD', 'order': 300}, 'net_income_loss_attributable_to_parent': {'label': 'Net Income/Loss Attributable To Parent', 'value': -18123000.0, 'unit': 'USD', 'order': 3500}, 'basic_earnings_per_share': {'label': 'Basic Earnings Per Share', 'value': -0.17, 'unit': 'USD / shares', 'order': 4200}, 'revenues': {'label': 'Revenues', 'value': 127327000.0, 'unit': 'USD', 'order': 100}}, 'balance_sheet': {'current_liabilities': {'label': 'Current Liabilities', 'value': 62451000.0, 'unit': 'USD', 'order': 700}, 'liabilities_and_equity': {'label': 'Liabilities And Equity', 'value': 1956828000.0, 'unit': 'USD', 'order': 1900}, 'noncurrent_assets': {'label': 'Noncurrent Assets', 'value': 344924000.0, 'unit': 'USD', 'order': 300}, 'other_than_fixed_noncurrent_assets': {'label': 'Other Than Fixed Noncurrent Assets', 'value': 85539000.0, 'unit': 'USD', 'order': 500}, 'equity_attributable_to_noncontrolling_interest': {'label': 'Equity Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 1500}, 'current_assets': {'label': 'Current Assets', 'value': 1611904000.0, 'unit': 'USD', 'order': 200}, 'equity': {'label': 'Equity', 'value': 427831000.0, 'unit': 'USD', 'order': 1400}, 'assets': {'label': 'Assets', 'value': 1956828000.0, 'unit': 'USD', 'order': 100}, 'noncurrent_liabilities': {'label': 'Noncurrent Liabilities', 'value': 1466546000.0, 'unit': 'USD', 'order': 800}, 'fixed_assets': {'label': 'Fixed Assets', 'value': 259385000.0, 'unit': 'USD', 'order': 400}, 'liabilities': {'label': 'Liabilities', 'value': 1528997000.0, 'unit': 'USD', 'order': 600}, 'equity_attributable_to_parent': {'label': 'Equity Attributable To Parent', 'value': 427831000.0, 'unit': 'USD', 'order': 1600}}, 'cash_flow_statement': {'net_cash_flow_from_operating_activities_continuing': {'label': 'Net Cash Flow From Operating Activities, Continuing', 'value': 30283000.0, 'unit': 'USD', 'order': 200}, 'net_cash_flow_from_investing_activities_continuing': {'label': 'Net Cash Flow From Investing Activities, Continuing', 'value': -1120955000.0, 'unit': 'USD', 'order': 500}, 'net_cash_flow_from_financing_activities_continuing': {'label': 'Net Cash Flow From Financing Activities, Continuing', 'value': -157879000.0, 'unit': 'USD', 'order': 800}, 'net_cash_flow_continuing': {'label': 'Net Cash Flow, Continuing', 'value': -1248551000.0, 'unit': 'USD', 'order': 1200}, 'net_cash_flow': {'label': 'Net Cash Flow', 'value': -1248551000.0, 'unit': 'USD', 'order': 1100}, 'net_cash_flow_from_operating_activities': {'label': 'Net Cash Flow From Operating Activities', 'value': 30283000.0, 'unit': 'USD', 'order': 100}, 'net_cash_flow_from_financing_activities': {'label': 'Net Cash Flow From Financing Activities', 'value': -157879000.0, 'unit': 'USD', 'order': 700}, 'net_cash_flow_from_investing_activities': {'label': 'Net Cash Flow From Investing Activities', 'value': -1120955000.0, 'unit': 'USD', 'order': 400}}}, 'start_date': '2022-01-01', 'end_date': '2022-03-31', 'filing_date': '2022-05-05', 'cik': '0001582961', 'company_name': 'DigitalOcean Holdings, Inc.', 'fiscal_period': 'Q1', 'fiscal_year': '2022', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-22-000023', 'source_filing_file_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-22-000023/files/docn-20220331_htm.xml'}], 'status': 'OK', 'request_id': '351a69b3005f88238e7b3ad7ba5a4412', 'count': 1, 'next_url': 'https://api.polygon.io/vX/reference/financials?cursor=YXA9MjAyMjAzMzEmYXM9MDAwMTU4Mjk2MS0yMi0wMDAwMjMmZW50aXRpZXMuY29tcGFueV9kYXRhLnRpY2tlcj1ET0NOJmhhc194YnJsPXRydWUmbGltaXQ9MSZzb3J0PXBlcmlvZF9vZl9yZXBvcnRfZGF0ZSZ0eXBlPTEwLVE'}\n", - "array_cells": [ - [8, 14], - [9, 14], - [10, 14], - [11, 14] - ], - "evaluation_result": { - "success": true, - "std_out": "{'results': [{'id': '0001582961:TTM', 'start_date': '2022-01-01', 'end_date': '2022-12-31', 'filing_date': '2023-02-22', 'timeframe': 'ttm', 'fiscal_period': 'TTM', 'fiscal_year': '2022', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-23-000009', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001582961-23-000009/files/docn-20221231_htm.xml', 'financials': {'cash_flow_statement': {'net_cash_flow_from_investing_activities_continuing': {'value': -1148158000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'exchange_gains_losses': {'value': -249000, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow_from_operating_activities': {'value': 195152000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow': {'value': -1563618000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities_continuing': {'value': -610363000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_operating_activities_continuing': {'value': 195152000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities': {'value': -610363000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_continuing': {'value': -1563369000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_investing_activities': {'value': -1148158000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_parent': {'value': -25957000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss': {'value': -25957000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -1674000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': -25957000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}, 'income_statement': {'benefits_costs_expenses': {'value': 600729000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'net_income_loss_attributable_to_parent': {'value': -24283000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -24283000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'basic_earnings_per_share': {'value': -0.24, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss': {'value': -24283000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'operating_expenses': {'value': 390614000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_tax_expense_benefit_deferred': {'value': -4383000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'income_tax_expense_benefit': {'value': -124000, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'income_tax_expense_benefit_current': {'value': 4259000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Current', 'order': 2300}, 'income_loss_from_continuing_operations_after_tax': {'value': -24283000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'income_loss_from_continuing_operations_before_tax': {'value': -24407000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'operating_income_loss': {'value': -26219000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'diluted_earnings_per_share': {'value': -0.24, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'costs_and_expenses': {'value': 600729000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'cost_of_revenue': {'value': 211927000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'gross_profit': {'value': 364395000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'nonoperating_income_loss': {'value': 1812000.0, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'interest_expense_operating': {'value': 8396000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'revenues': {'value': 576322000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}}, 'balance_sheet': {'current_liabilities': {'value': 164270000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'noncurrent_liabilities': {'value': 1600548000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'temporary_equity': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity', 'order': 1700}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'liabilities': {'value': 1764818000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'current_assets': {'value': 946552000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'assets': {'value': 1815908000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_assets': {'value': 869356000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity': {'value': 51090000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'other_than_fixed_noncurrent_assets': {'value': 596186000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'temporary_equity_attributable_to_parent': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity Attributable To Parent', 'order': 1800}, 'fixed_assets': {'value': 273170000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'liabilities_and_equity': {'value': 1815908000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity_attributable_to_parent': {'value': 51090000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}}}}, {'id': '0001582961:2022:Q4', 'start_date': '2022-10-01', 'end_date': '2022-12-31', 'timeframe': 'quarterly', 'fiscal_period': 'Q4', 'fiscal_year': '2022', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'financials': {'comprehensive_income': {'comprehensive_income_loss': {'value': -7806000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': 2260000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_parent': {'value': -7806000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss': {'value': -7806000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}}, 'cash_flow_statement': {'net_cash_flow_from_investing_activities': {'value': 51584000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities_continuing': {'value': 65144000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities_continuing': {'value': 178000, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow': {'value': 116657000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_continuing': {'value': 116906000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities': {'value': 178000, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities': {'value': 65144000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities_continuing': {'value': 51584000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}}, 'balance_sheet': {'equity_attributable_to_parent': {'value': 51090000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'noncurrent_assets': {'value': 869356000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'current_liabilities': {'value': 164270000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'liabilities_and_equity': {'value': 1815908000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'liabilities': {'value': 1764818000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'current_assets': {'value': 946552000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'temporary_equity_attributable_to_parent': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity Attributable To Parent', 'order': 1800}, 'assets': {'value': 1815908000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_liabilities': {'value': 1600548000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity': {'value': 51090000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'temporary_equity': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity', 'order': 1700}, 'fixed_assets': {'value': 273170000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'other_than_fixed_noncurrent_assets': {'value': 596186000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}}, 'income_statement': {'gross_profit': {'value': 99610000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'nonoperating_income_loss': {'value': 2294000.0, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'income_loss_from_continuing_operations_after_tax': {'value': -10066000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'income_tax_expense_benefit': {'value': -2735000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'income_loss_from_continuing_operations_before_tax': {'value': -10066000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'diluted_earnings_per_share': {'value': -0.09999999999999998, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss': {'value': -10066000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'cost_of_revenue': {'value': 63388000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'costs_and_expenses': {'value': 175799000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'interest_expense_operating': {'value': 2115000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -10066000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'basic_earnings_per_share': {'value': -0.09999999999999998, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'revenues': {'value': 162998000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'net_income_loss_attributable_to_parent': {'value': -10066000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'operating_expenses': {'value': 114705000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'operating_income_loss': {'value': -15095000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'benefits_costs_expenses': {'value': 175799000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}}}}, {'id': '0001582961:2022:FY', 'start_date': '2022-01-01', 'end_date': '2022-12-31', 'filing_date': '2023-02-22', 'timeframe': 'annual', 'fiscal_period': 'FY', 'fiscal_year': '2022', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-23-000009', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001582961-23-000009/files/docn-20221231_htm.xml', 'financials': {'cash_flow_statement': {'exchange_gains_losses': {'value': -249000, 'unit': 'USD', 'label': 'Exchange Gains/Losses', 'order': 1000}, 'net_cash_flow_from_investing_activities': {'value': -1148158000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow': {'value': -1563618000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_continuing': {'value': -1563369000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_investing_activities_continuing': {'value': -1148158000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities_continuing': {'value': 195152000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_operating_activities': {'value': 195152000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_financing_activities_continuing': {'value': -610363000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_financing_activities': {'value': -610363000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}}, 'income_statement': {'net_income_loss_available_to_common_stockholders_basic': {'value': -24283000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'basic_earnings_per_share': {'value': -0.24, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss_attributable_to_parent': {'value': -24283000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'income_loss_from_continuing_operations_after_tax': {'value': -24283000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'benefits_costs_expenses': {'value': 600729000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'costs_and_expenses': {'value': 600729000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'income_tax_expense_benefit_deferred': {'value': -4383000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'revenues': {'value': 576322000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'income_tax_expense_benefit_current': {'value': 4259000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Current', 'order': 2300}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'net_income_loss': {'value': -24283000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'nonoperating_income_loss': {'value': 1812000.0, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'cost_of_revenue': {'value': 211927000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'interest_expense_operating': {'value': 8396000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'operating_expenses': {'value': 390614000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'income_tax_expense_benefit': {'value': -124000, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'operating_income_loss': {'value': -26219000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'income_loss_from_continuing_operations_before_tax': {'value': -24407000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'diluted_earnings_per_share': {'value': -0.24, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'gross_profit': {'value': 364395000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}}, 'comprehensive_income': {'comprehensive_income_loss': {'value': -25957000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -1674000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss': {'value': -25957000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'value': -25957000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'balance_sheet': {'assets': {'value': 1815908000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'other_than_fixed_noncurrent_assets': {'value': 596186000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'liabilities_and_equity': {'value': 1815908000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'current_assets': {'value': 946552000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'noncurrent_liabilities': {'value': 1600548000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'fixed_assets': {'value': 273170000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'liabilities': {'value': 1764818000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'temporary_equity': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity', 'order': 1700}, 'noncurrent_assets': {'value': 869356000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity': {'value': 51090000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'equity_attributable_to_parent': {'value': 51090000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'current_liabilities': {'value': 164270000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'temporary_equity_attributable_to_parent': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity Attributable To Parent', 'order': 1800}}}}, {'id': '0001582961:2022:Q3', 'start_date': '2022-07-01', 'end_date': '2022-09-30', 'filing_date': '2022-11-07', 'timeframe': 'quarterly', 'fiscal_period': 'Q3', 'fiscal_year': '2022', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-22-000051', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001582961-22-000051/files/docn-20220930_htm.xml', 'financials': {'income_statement': {'basic_earnings_per_share': {'value': 0.1, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'interest_expense_operating': {'value': 2127000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'nonoperating_income_loss': {'value': 1147000.0, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'income_tax_expense_benefit': {'value': 442000, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 10097000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'benefits_costs_expenses': {'value': 141576000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'gross_profit': {'value': 97579000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'income_loss_from_continuing_operations_before_tax': {'value': 10539000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'revenues': {'value': 152115000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'diluted_earnings_per_share': {'value': 0.1, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'costs_and_expenses': {'value': 141576000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'operating_expenses': {'value': 88187000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'net_income_loss_attributable_to_parent': {'value': 10097000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'net_income_loss': {'value': 10097000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'operating_income_loss': {'value': 9392000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'cost_of_revenue': {'value': 54536000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'income_loss_from_continuing_operations_after_tax': {'value': 10097000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}}, 'cash_flow_statement': {'net_cash_flow_from_financing_activities_continuing': {'value': -52759000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_financing_activities': {'value': -52759000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_continuing': {'value': -38961000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow': {'value': -38961000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_operating_activities': {'value': 54356000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities_continuing': {'value': -40558000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities_continuing': {'value': 54356000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities': {'value': -40558000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_parent': {'value': 10757000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': 660000, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss': {'value': 10757000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss': {'value': 10757000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}, 'balance_sheet': {'liabilities_and_equity': {'value': 1623687000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'other_than_fixed_noncurrent_assets': {'value': 444346000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'noncurrent_assets': {'value': 715331000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'assets': {'value': 1623687000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_liabilities': {'value': 1494662000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'liabilities': {'value': 1593470000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'equity_attributable_to_parent': {'value': 30217000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'equity': {'value': 30217000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'current_liabilities': {'value': 98808000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'fixed_assets': {'value': 270985000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'current_assets': {'value': 908356000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}}}}, {'id': '0001582961:2022:Q2', 'start_date': '2022-04-01', 'end_date': '2022-06-30', 'filing_date': '2022-08-08', 'timeframe': 'quarterly', 'fiscal_period': 'Q2', 'fiscal_year': '2022', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-22-000039', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001582961-22-000039/files/docn-20220630_htm.xml', 'financials': {'cash_flow_statement': {'net_cash_flow_from_operating_activities': {'value': 45369000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_financing_activities': {'value': -399903000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_investing_activities': {'value': -38229000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow': {'value': -392763000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_investing_activities_continuing': {'value': -38229000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_continuing': {'value': -392763000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_operating_activities_continuing': {'value': 45369000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities_continuing': {'value': -399903000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_parent': {'value': -8859000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss': {'value': -8859000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -2668000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss': {'value': -8859000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}}, 'income_statement': {'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -6191000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'net_income_loss_attributable_to_parent': {'value': -6191000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'benefits_costs_expenses': {'value': 141242000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'income_loss_from_continuing_operations_before_tax': {'value': -7360000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'income_loss_from_continuing_operations_after_tax': {'value': -6191000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'costs_and_expenses': {'value': 141242000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'operating_expenses': {'value': 94013000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'nonoperating_income_loss': {'value': 17000, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'revenues': {'value': 133882000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'net_income_loss': {'value': -6191000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'diluted_earnings_per_share': {'value': -0.06, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'interest_expense_operating': {'value': 2095000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'basic_earnings_per_share': {'value': -0.06, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'operating_income_loss': {'value': -7377000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'gross_profit': {'value': 86636000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_tax_expense_benefit': {'value': -1169000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'cost_of_revenue': {'value': 47246000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}}, 'balance_sheet': {'fixed_assets': {'value': 268418000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'current_liabilities': {'value': 74227000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'equity_attributable_to_parent': {'value': 48273000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'equity': {'value': 48273000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'liabilities': {'value': 1542435000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'assets': {'value': 1590708000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_assets': {'value': 359576000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'other_than_fixed_noncurrent_assets': {'value': 91158000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'noncurrent_liabilities': {'value': 0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'liabilities_and_equity': {'value': 1590708000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'current_assets': {'value': 1231132000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}}}}, {'id': '0001582961:2022:Q1', 'start_date': '2022-01-01', 'end_date': '2022-03-31', 'filing_date': '2022-05-05', 'timeframe': 'quarterly', 'fiscal_period': 'Q1', 'fiscal_year': '2022', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-22-000023', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001582961-22-000023/files/docn-20220331_htm.xml', 'financials': {'balance_sheet': {'noncurrent_liabilities': {'value': 0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'current_liabilities': {'value': 62451000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'equity': {'value': 427831000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'other_than_fixed_noncurrent_assets': {'value': 85539000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'liabilities': {'value': 1528997000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'noncurrent_assets': {'value': 344924000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'assets': {'value': 1956828000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'equity_attributable_to_parent': {'value': 427831000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'liabilities_and_equity': {'value': 1956828000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'fixed_assets': {'value': 259385000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'current_assets': {'value': 1611904000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}}, 'income_statement': {'income_loss_from_continuing_operations_before_tax': {'value': -14785000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss': {'value': -18123000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'income_loss_from_continuing_operations_after_tax': {'value': -18123000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'gross_profit': {'value': 80570000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'income_tax_expense_benefit': {'value': 3338000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'basic_earnings_per_share': {'value': -0.17, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss_attributable_to_parent': {'value': -18123000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'revenues': {'value': 127327000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'operating_expenses': {'value': 93709000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'operating_income_loss': {'value': -13139000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -18123000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'nonoperating_income_loss': {'value': -1646000.0, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'benefits_costs_expenses': {'value': 142112000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'diluted_earnings_per_share': {'value': -0.17, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'cost_of_revenue': {'value': 46757000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'costs_and_expenses': {'value': 142112000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'interest_expense_operating': {'value': 2059000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}}, 'cash_flow_statement': {'net_cash_flow_from_investing_activities_continuing': {'value': -1120955000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities': {'value': 30283000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities': {'value': -1120955000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_continuing': {'value': -1248551000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities_continuing': {'value': -157879000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_financing_activities': {'value': -157879000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow': {'value': -1248551000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_operating_activities_continuing': {'value': 30283000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': -20049000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': -20049000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss': {'value': -20049000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -1926000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}}}}, {'id': '0001582961:2021:Q4', 'start_date': '2021-10-01', 'end_date': '2021-12-31', 'timeframe': 'quarterly', 'fiscal_period': 'Q4', 'fiscal_year': '2021', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'financials': {'comprehensive_income': {'comprehensive_income_loss': {'value': -12153000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': -12153000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -28000, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss': {'value': -12153000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}}, 'cash_flow_statement': {'net_cash_flow': {'value': 1123449000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_operating_activities': {'value': 32738000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities_continuing': {'value': -32401000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_investing_activities': {'value': -32401000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities_continuing': {'value': 32738000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_continuing': {'value': 1123449000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities_continuing': {'value': 1123112000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_financing_activities': {'value': 1123112000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}}, 'income_statement': {'operating_income_loss': {'value': -10139000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'costs_and_expenses': {'value': 130863000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'operating_expenses': {'value': 85401000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'income_loss_from_continuing_operations_after_tax': {'value': -12125000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'basic_earnings_per_share': {'value': -0.13, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'gross_profit': {'value': 75262000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'net_income_loss_attributable_to_parent': {'value': -12125000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'diluted_earnings_per_share': {'value': -0.13, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'net_income_loss': {'value': -12125000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'benefits_costs_expenses': {'value': 130863000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'revenues': {'value': 119662000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'income_tax_expense_benefit': {'value': 924000, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'nonoperating_income_loss': {'value': -1062000.0, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'interest_expense_operating': {'value': 1069000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'income_loss_from_continuing_operations_before_tax': {'value': -11201000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -12125000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'cost_of_revenue': {'value': 44400000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}}, 'balance_sheet': {'liabilities': {'value': 1522798000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'temporary_equity': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity', 'order': 1700}, 'temporary_equity_attributable_to_parent': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity Attributable To Parent', 'order': 1800}, 'liabilities_and_equity': {'value': 2100995000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'assets': {'value': 2100995000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'equity': {'value': 578197000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'current_liabilities': {'value': 58239000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'fixed_assets': {'value': 249643000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'noncurrent_assets': {'value': 330939000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity_attributable_to_parent': {'value': 578197000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'other_than_fixed_noncurrent_assets': {'value': 81296000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'noncurrent_liabilities': {'value': 1464559000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'current_assets': {'value': 1770056000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}}}}, {'id': '0001582961:2021:FY', 'start_date': '2021-01-01', 'end_date': '2021-12-31', 'filing_date': '2022-02-25', 'timeframe': 'annual', 'fiscal_period': 'FY', 'fiscal_year': '2021', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-22-000010', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001582961-22-000010/files/docn-20211231_htm.xml', 'financials': {'cash_flow_statement': {'net_cash_flow_continuing': {'value': 1612888000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_operating_activities_continuing': {'value': 133114000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities_continuing': {'value': -113605000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_financing_activities': {'value': 1593379000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_investing_activities': {'value': -113605000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_financing_activities_continuing': {'value': 1593379000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_operating_activities': {'value': 133114000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow': {'value': 1612888000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}}, 'comprehensive_income': {'other_comprehensive_income_loss': {'value': -19632000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'value': -19632000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': -19632000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -129000, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}}, 'income_statement': {'net_income_loss_available_to_common_stockholders_basic': {'value': -19503000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'income_loss_from_continuing_operations_after_tax': {'value': -19503000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_tax_expense_benefit_current': {'value': 1285000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Current', 'order': 2300}, 'operating_income_loss': {'value': -11186000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'nonoperating_income_loss': {'value': -7015000.0, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'operating_expenses': {'value': 269152000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'income_tax_expense_benefit': {'value': 1302000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'costs_and_expenses': {'value': 446762000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'diluted_earnings_per_share': {'value': -0.21, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'gross_profit': {'value': 257966000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'net_income_loss': {'value': -19503000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'revenues': {'value': 428561000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'net_income_loss_attributable_to_parent': {'value': -19503000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'income_loss_from_continuing_operations_before_tax': {'value': -18201000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'income_tax_expense_benefit_deferred': {'value': 17000, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'basic_earnings_per_share': {'value': -0.21, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'benefits_costs_expenses': {'value': 446762000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'interest_expense_operating': {'value': 3744000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'cost_of_revenue': {'value': 170595000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}}, 'balance_sheet': {'liabilities': {'value': 1522798000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'assets': {'value': 2100995000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_liabilities': {'value': 1464559000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity': {'value': 578197000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'noncurrent_assets': {'value': 330939000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'temporary_equity_attributable_to_parent': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity Attributable To Parent', 'order': 1800}, 'liabilities_and_equity': {'value': 2100995000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'current_liabilities': {'value': 58239000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'current_assets': {'value': 1770056000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity_attributable_to_parent': {'value': 578197000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'fixed_assets': {'value': 249643000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'temporary_equity': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity', 'order': 1700}, 'other_than_fixed_noncurrent_assets': {'value': 81296000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}}}}, {'id': '0001582961:2021:Q3', 'start_date': '2021-07-01', 'end_date': '2021-09-30', 'filing_date': '2021-11-05', 'timeframe': 'quarterly', 'fiscal_period': 'Q3', 'fiscal_year': '2021', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-21-000027', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001582961-21-000027/files/docn-20210930_htm.xml', 'financials': {'balance_sheet': {'noncurrent_assets': {'value': 323042000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'temporary_equity_attributable_to_parent': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity Attributable To Parent', 'order': 1800}, 'liabilities_and_equity': {'value': 965825000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'current_assets': {'value': 642783000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'temporary_equity': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity', 'order': 1700}, 'equity': {'value': 906433000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'liabilities': {'value': 59392000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'other_than_fixed_noncurrent_assets': {'value': 81959000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'noncurrent_liabilities': {'value': 1815000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'fixed_assets': {'value': 241083000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_parent': {'value': 906433000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'current_liabilities': {'value': 57577000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'assets': {'value': 965825000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}}, 'cash_flow_statement': {'net_cash_flow_continuing': {'value': 12532000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_investing_activities': {'value': -31536000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_financing_activities': {'value': 3889000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities_continuing': {'value': 40179000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow': {'value': 12532000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities_continuing': {'value': 3889000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': -31536000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities': {'value': 40179000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}}, 'comprehensive_income': {'other_comprehensive_income_loss': {'value': -1925000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -73000, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss_attributable_to_parent': {'value': -1925000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss': {'value': -1925000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}, 'income_statement': {'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'operating_income_loss': {'value': -1671000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'basic_earnings_per_share': {'value': -0.02, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'revenues': {'value': 111428000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'nonoperating_income_loss': {'value': -326000, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'operating_expenses': {'value': 69593000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'benefits_costs_expenses': {'value': 113425000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'diluted_earnings_per_share': {'value': -0.02, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss': {'value': -1852000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'income_loss_from_continuing_operations_before_tax': {'value': -1997000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'gross_profit': {'value': 67922000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'interest_expense_operating': {'value': 186000, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'costs_and_expenses': {'value': 113425000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -1852000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'income_tax_expense_benefit': {'value': -145000, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'net_income_loss_attributable_to_parent': {'value': -1852000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'cost_of_revenue': {'value': 43506000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'income_loss_from_continuing_operations_after_tax': {'value': -1852000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}}}}, {'id': '0001582961:2021:Q2', 'start_date': '2021-04-01', 'end_date': '2021-06-30', 'filing_date': '2021-08-06', 'timeframe': 'quarterly', 'fiscal_period': 'Q2', 'fiscal_year': '2021', 'cik': '0001582961', 'sic': '7370', 'tickers': ['DOCN'], 'company_name': 'DigitalOcean Holdings, Inc.', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001582961-21-000020', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001582961-21-000020/files/docn-20210630_htm.xml', 'financials': {'income_statement': {'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'operating_income_loss': {'value': -2630000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'operating_expenses': {'value': 63295000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'interest_expense_operating': {'value': 233000, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'income_loss_from_continuing_operations_before_tax': {'value': -2660000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'costs_and_expenses': {'value': 106470000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'gross_profit': {'value': 60665000.0, 'unit': 'USD', 'label': 'Gross Profit', 'order': 800}, 'revenues': {'value': 103810000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'basic_earnings_per_share': {'value': -0.02, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'cost_of_revenue': {'value': 43145000.0, 'unit': 'USD', 'label': 'Cost Of Revenue', 'order': 300}, 'income_tax_expense_benefit': {'value': -473000, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'benefits_costs_expenses': {'value': 106470000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'net_income_loss_attributable_to_parent': {'value': -2187000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'net_income_loss': {'value': -2187000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -2187000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'diluted_earnings_per_share': {'value': -0.02, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'nonoperating_income_loss': {'value': -30000, 'unit': 'USD', 'label': 'Nonoperating Income/Loss', 'order': 900}, 'income_loss_from_continuing_operations_after_tax': {'value': -2187000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}}, 'comprehensive_income': {'comprehensive_income_loss': {'value': -2227000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': -2227000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss': {'value': -2227000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -40000, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}}, 'cash_flow_statement': {'net_cash_flow_from_investing_activities_continuing': {'value': -25981000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_financing_activities': {'value': 2740000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_financing_activities_continuing': {'value': 2740000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities': {'value': -25981000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow': {'value': 17165000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_operating_activities': {'value': 40406000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_continuing': {'value': 17165000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_operating_activities_continuing': {'value': 40406000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}}, 'balance_sheet': {'noncurrent_liabilities': {'value': 0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'current_assets': {'value': 629117000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'temporary_equity': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity', 'order': 1700}, 'equity_attributable_to_parent': {'value': 858084000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'equity_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'noncurrent_assets': {'value': 286313000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'current_liabilities': {'value': 55387000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'assets': {'value': 915430000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'temporary_equity_attributable_to_parent': {'value': 0, 'unit': 'USD', 'label': 'Temporary Equity Attributable To Parent', 'order': 1800}, 'equity': {'value': 858084000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'liabilities': {'value': 57346000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'fixed_assets': {'value': 243050000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'other_than_fixed_noncurrent_assets': {'value': 43263000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'liabilities_and_equity': {'value': 915430000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}}}}], 'status': 'OK', 'request_id': '67c32eed13747758ec17b91c1ebcf716', 'next_url': 'https://api.polygon.io/vX/reference/financials?cursor=YXA9MDAwMTU4Mjk2MSUzQTIwMjElM0FRMiZhcz0mbGltaXQ9MTAmcGVyaW9kX29mX3JlcG9ydF9kYXRlLmx0ZT0yMDIxLTA2LTMwJnNvcnQ9cGVyaW9kX29mX3JlcG9ydF9kYXRlJnRpY2tlcj1ET0NO'}\n", - "output_value": " 0 1 2 3\n0 DigitalOcean Holdings, Inc. 576322000.0 3365348452.44 5.839354479683233", - "cells_accessed": [[7, 14]], - "array_output": [["DigitalOcean Holdings, Inc.", "576322000.0", "3365348452.44", "5.839354479683233"]], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 14)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nprint(stock_financials_json)\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - } - }, - { - "x": 8, - "y": 15, - "type": "PYTHON", - "value": "Oracle Corp", - "python_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 15)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nprint(stock_financials_json)\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "last_modified": "2023-03-21T19:55:08.809Z", - "python_output": "{'results': [{'financials': {'balance_sheet': {'equity_attributable_to_parent': {'label': 'Equity Attributable To Parent', 'value': -8696000000.0, 'unit': 'USD', 'order': 1600}, 'fixed_assets': {'label': 'Fixed Assets', 'value': 8609000000.0, 'unit': 'USD', 'order': 400}, 'noncurrent_liabilities': {'label': 'Noncurrent Liabilities', 'value': 96022000000.0, 'unit': 'USD', 'order': 800}, 'current_assets': {'label': 'Current Assets', 'value': 31675000000.0, 'unit': 'USD', 'order': 200}, 'equity': {'label': 'Equity', 'value': -8211000000.0, 'unit': 'USD', 'order': 1400}, 'liabilities': {'label': 'Liabilities', 'value': 116855000000.0, 'unit': 'USD', 'order': 600}, 'equity_attributable_to_noncontrolling_interest': {'label': 'Equity Attributable To Noncontrolling Interest', 'value': 485000000.0, 'unit': 'USD', 'order': 1500}, 'commitments_and_contingencies': {'label': 'Commitments and Contingencies', 'value': 0, 'unit': 'USD', 'order': 900}, 'liabilities_and_equity': {'label': 'Liabilities And Equity', 'value': 108644000000.0, 'unit': 'USD', 'order': 1900}, 'noncurrent_assets': {'label': 'Noncurrent Assets', 'value': 76969000000.0, 'unit': 'USD', 'order': 300}, 'current_liabilities': {'label': 'Current Liabilities', 'value': 20833000000.0, 'unit': 'USD', 'order': 700}, 'assets': {'label': 'Assets', 'value': 108644000000.0, 'unit': 'USD', 'order': 100}, 'other_than_fixed_noncurrent_assets': {'label': 'Other Than Fixed Noncurrent Assets', 'value': 76969000000.0, 'unit': 'USD', 'order': 500}}, 'cash_flow_statement': {}, 'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'value': -62000000.0, 'unit': 'USD', 'order': 600}, 'comprehensive_income_loss': {'label': 'Comprehensive Income/Loss', 'value': 2257000000.0, 'unit': 'USD', 'order': 100}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 200}, 'other_comprehensive_income_loss': {'label': 'Other Comprehensive Income/Loss', 'value': 2257000000.0, 'unit': 'USD', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'label': 'Comprehensive Income/Loss Attributable To Parent', 'value': 2257000000.0, 'unit': 'USD', 'order': 300}}, 'income_statement': {'basic_earnings_per_share': {'label': 'Basic Earnings Per Share', 'value': 0.87, 'unit': 'USD / shares', 'order': 4200}, 'net_income_loss': {'label': 'Net Income/Loss', 'value': 2319000000.0, 'unit': 'USD', 'order': 3200}, 'operating_expenses': {'label': 'Operating Expenses', 'value': -3822000000.0, 'unit': 'USD', 'order': 1000}, 'interest_expense_operating': {'label': 'Interest Expense, Operating', 'value': 667000000.0, 'unit': 'USD', 'order': 2700}, 'income_loss_from_continuing_operations_after_tax': {'label': 'Income/Loss From Continuing Operations After Tax', 'value': 2319000000.0, 'unit': 'USD', 'order': 1400}, 'net_income_loss_attributable_to_parent': {'label': 'Net Income/Loss Attributable To Parent', 'value': 2319000000.0, 'unit': 'USD', 'order': 3500}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'value': 0, 'unit': 'USD', 'order': 3800}, 'operating_income_loss': {'label': 'Operating Income/Loss', 'value': 3822000000.0, 'unit': 'USD', 'order': 1100}, 'revenues': {'label': 'Revenues', 'value': 10513000000.0, 'unit': 'USD', 'order': 100}, 'income_tax_expense_benefit': {'label': 'Income Tax Expense/Benefit', 'value': 521000000.0, 'unit': 'USD', 'order': 2200}, 'preferred_stock_dividends_and_other_adjustments': {'label': 'Preferred Stock Dividends And Other Adjustments', 'value': 0, 'unit': 'USD', 'order': 3900}, 'net_income_loss_available_to_common_stockholders_basic': {'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'value': 2319000000.0, 'unit': 'USD', 'order': 3700}, 'net_income_loss_attributable_to_noncontrolling_interest': {'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'value': 0, 'unit': 'USD', 'order': 3300}, 'costs_and_expenses': {'label': 'Costs And Expenses', 'value': 6691000000.0, 'unit': 'USD', 'order': 600}, 'diluted_earnings_per_share': {'label': 'Diluted Earnings Per Share', 'value': 0.84, 'unit': 'USD / shares', 'order': 4300}, 'benefits_costs_expenses': {'label': 'Benefits Costs and Expenses', 'value': 6691000000.0, 'unit': 'USD', 'order': 200}, 'income_loss_from_continuing_operations_before_tax': {'label': 'Income/Loss From Continuing Operations Before Tax', 'value': 3822000000.0, 'unit': 'USD', 'order': 1500}}}, 'start_date': '2021-12-01', 'end_date': '2022-02-28', 'filing_date': '2022-03-11', 'cik': '0001341439', 'company_name': 'Oracle Corporation', 'fiscal_period': 'Q3', 'fiscal_year': '2022', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-009859', 'source_filing_file_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-009859/files/orcl-10q_20220228_htm.xml'}], 'status': 'OK', 'request_id': 'dfe4c25962a324b3e7064c320e4677dd', 'count': 1, 'next_url': 'https://api.polygon.io/vX/reference/financials?cursor=YXA9MjAyMjAyMjgmYXM9MDAwMTU2NDU5MC0yMi0wMDk4NTkmZW50aXRpZXMuY29tcGFueV9kYXRhLnRpY2tlcj1PUkNMJmhhc194YnJsPXRydWUmbGltaXQ9MSZzb3J0PXBlcmlvZF9vZl9yZXBvcnRfZGF0ZSZ0eXBlPTEwLVE'}\n", - "array_cells": [ - [8, 15], - [9, 15], - [10, 15], - [11, 15] - ], - "evaluation_result": { - "success": true, - "std_out": "{'results': [{'id': '0001341439:TTM', 'start_date': '2022-03-01', 'end_date': '2023-02-28', 'timeframe': 'ttm', 'fiscal_period': 'TTM', 'fiscal_year': '', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'financials': {'cash_flow_statement': {'net_cash_flow_from_operating_activities': {'value': 15503000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_continuing': {'value': -14206000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_operating_activities_continuing': {'value': 15503000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities': {'value': -36033000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_financing_activities_continuing': {'value': 6324000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': -36033000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow': {'value': -14206000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities': {'value': 6324000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}}, 'income_statement': {'net_income_loss': {'value': 8557000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_attributable_to_parent': {'value': 8373000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'revenues': {'value': 78558000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'operating_expenses': {'value': 34503000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'interest_expense_operating': {'value': 3254000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'operating_income_loss': {'value': 13455000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'income_tax_expense_benefit_deferred': {'value': -1416000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'income_loss_from_continuing_operations_before_tax': {'value': 51393000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 184000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'income_loss_from_continuing_operations_after_tax': {'value': 47624000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'benefits_costs_expenses': {'value': 27165000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'diluted_earnings_per_share': {'value': 3.0300000000000002, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 8373000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'costs_and_expenses': {'value': 27165000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'income_tax_expense_benefit': {'value': 1268000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'basic_earnings_per_share': {'value': 3.12, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}}, 'balance_sheet': {'equity_attributable_to_parent': {'value': -2421000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'equity': {'value': -1912000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'other_than_fixed_noncurrent_assets': {'value': 112924000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'equity_attributable_to_noncontrolling_interest': {'value': 509000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'liabilities_and_equity': {'value': 131620000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'fixed_assets': {'value': 16345000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'noncurrent_assets': {'value': 112924000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'liabilities': {'value': 133532000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'noncurrent_liabilities': {'value': 110652000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'current_assets': {'value': 18696000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'current_liabilities': {'value': 22880000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'assets': {'value': 131620000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}}, 'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'value': -16000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss': {'value': 8357000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss': {'value': 1590000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_parent': {'value': 8357000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}}}}, {'id': '0001341439:2023:Q3', 'start_date': '2022-12-01', 'end_date': '2023-02-28', 'filing_date': '2023-03-10', 'timeframe': 'quarterly', 'fiscal_period': 'Q3', 'fiscal_year': '2023', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-23-003413', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-23-003413/files/orcl-10q_20230228_htm.xml', 'financials': {'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'value': 83000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_parent': {'value': 1979000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss': {'value': 1979000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': 1979000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}}, 'income_statement': {'income_tax_expense_benefit_deferred': {'value': -401000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'income_tax_expense_benefit': {'value': 322000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'operating_expenses': {'value': 9138000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'interest_expense_operating': {'value': 908000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'operating_income_loss': {'value': 3260000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss': {'value': 1896000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_attributable_to_parent': {'value': 1896000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'costs_and_expenses': {'value': 9138000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'basic_earnings_per_share': {'value': 0.7, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'revenues': {'value': 12398000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'income_loss_from_continuing_operations_before_tax': {'value': 3260000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'benefits_costs_expenses': {'value': 9138000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 1896000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'income_loss_from_continuing_operations_after_tax': {'value': 1896000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'diluted_earnings_per_share': {'value': 0.68, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}}, 'balance_sheet': {'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'liabilities': {'value': 133532000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'assets': {'value': 131620000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'current_assets': {'value': 18696000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'liabilities_and_equity': {'value': 131620000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'fixed_assets': {'value': 16345000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity': {'value': -1912000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'equity_attributable_to_parent': {'value': -2421000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'noncurrent_liabilities': {'value': 110652000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'noncurrent_assets': {'value': 112924000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity_attributable_to_noncontrolling_interest': {'value': 509000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'current_liabilities': {'value': 22880000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'other_than_fixed_noncurrent_assets': {'value': 112924000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}}, 'cash_flow_statement': {'net_cash_flow_from_investing_activities_continuing': {'value': -2778000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_investing_activities': {'value': -2778000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_continuing': {'value': 1392000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow': {'value': 1392000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities': {'value': -105000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_financing_activities_continuing': {'value': -105000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_operating_activities': {'value': 4275000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_operating_activities_continuing': {'value': 4275000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}}}}, {'id': '0001341439:2023:Q2', 'start_date': '2022-09-01', 'end_date': '2022-11-30', 'filing_date': '2022-12-13', 'timeframe': 'quarterly', 'fiscal_period': 'Q2', 'fiscal_year': '2023', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-039278', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-22-039278/files/orcl-10q_20221130_htm.xml', 'financials': {'cash_flow_statement': {'net_cash_flow_from_financing_activities': {'value': -1855000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow': {'value': -3664000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_investing_activities_continuing': {'value': -2658000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities': {'value': 849000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_financing_activities_continuing': {'value': -1855000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_operating_activities_continuing': {'value': 849000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities': {'value': -2658000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_continuing': {'value': -3664000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}}, 'income_statement': {'income_tax_expense_benefit_deferred': {'value': -508000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'income_tax_expense_benefit': {'value': 403000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'net_income_loss_attributable_to_parent': {'value': 1741000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'operating_expenses': {'value': 9204000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'benefits_costs_expenses': {'value': 9204000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'diluted_earnings_per_share': {'value': 0.63, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'costs_and_expenses': {'value': 9204000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'basic_earnings_per_share': {'value': 0.65, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'income_loss_from_continuing_operations_after_tax': {'value': 1741000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'net_income_loss': {'value': 1741000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'interest_expense_operating': {'value': 856000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 1741000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'revenues': {'value': 12275000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'operating_income_loss': {'value': 3071000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'income_loss_from_continuing_operations_before_tax': {'value': 3071000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}}, 'balance_sheet': {'fixed_assets': {'value': 14351000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'other_than_fixed_noncurrent_assets': {'value': 110908000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'noncurrent_assets': {'value': 110908000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'current_liabilities': {'value': 27106000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'liabilities': {'value': 132245000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'liabilities_and_equity': {'value': 128469000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'equity': {'value': -3776000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'noncurrent_liabilities': {'value': 105139000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'current_assets': {'value': 17561000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity_attributable_to_parent': {'value': -4246000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'assets': {'value': 128469000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'equity_attributable_to_noncontrolling_interest': {'value': 470000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss': {'value': 1929000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': 188000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_parent': {'value': 1929000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss': {'value': 1929000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}}}}, {'id': '0001341439:2023:Q1', 'start_date': '2022-06-01', 'end_date': '2022-08-31', 'filing_date': '2022-09-13', 'timeframe': 'quarterly', 'fiscal_period': 'Q1', 'fiscal_year': '2023', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-031545', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-22-031545/files/orcl-10q_20220831_htm.xml', 'financials': {'comprehensive_income': {'comprehensive_income_loss': {'value': 1276000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -272000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'other_comprehensive_income_loss': {'value': 1276000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss_attributable_to_parent': {'value': 1276000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'balance_sheet': {'fixed_assets': {'value': 12280000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_noncontrolling_interest': {'value': 426000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'liabilities_and_equity': {'value': 130309000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'noncurrent_assets': {'value': 109305000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'other_than_fixed_noncurrent_assets': {'value': 109305000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'assets': {'value': 130309000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'equity': {'value': -5449000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'equity_attributable_to_parent': {'value': -5875000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'current_assets': {'value': 21004000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'current_liabilities': {'value': 34819000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'liabilities': {'value': 135758000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'noncurrent_liabilities': {'value': 100939000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}}, 'cash_flow_statement': {'net_cash_flow_from_financing_activities_continuing': {'value': 12310000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': -29436000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_investing_activities': {'value': -29436000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities': {'value': 6394000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow': {'value': -10732000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_continuing': {'value': -10732000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_operating_activities_continuing': {'value': 6394000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities': {'value': 12310000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}}, 'income_statement': {'operating_expenses': {'value': 8822000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'income_tax_expense_benefit_deferred': {'value': -344000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'net_income_loss': {'value': 1548000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'income_tax_expense_benefit': {'value': 108000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'revenues': {'value': 11445000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'costs_and_expenses': {'value': 8822000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_loss_from_continuing_operations_before_tax': {'value': 2623000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 1548000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'operating_income_loss': {'value': 2623000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'interest_expense_operating': {'value': 787000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'basic_earnings_per_share': {'value': 0.58, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'income_loss_from_continuing_operations_after_tax': {'value': 1548000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'diluted_earnings_per_share': {'value': 0.56, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'benefits_costs_expenses': {'value': 8822000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'net_income_loss_attributable_to_parent': {'value': 1548000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}}}}, {'id': '0001341439:2022:Q4', 'start_date': '2022-03-01', 'end_date': '2022-05-31', 'timeframe': 'quarterly', 'fiscal_period': 'Q4', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'financials': {'income_statement': {'basic_earnings_per_share': {'value': 1.1900000000000002, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'costs_and_expenses': {'value': 0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'income_tax_expense_benefit': {'value': 435000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'income_loss_from_continuing_operations_before_tax': {'value': 42440000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'diluted_earnings_per_share': {'value': 1.1500000000000001, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss_attributable_to_parent': {'value': 3189000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'income_loss_from_continuing_operations_after_tax': {'value': 42440000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 184000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'benefits_costs_expenses': {'value': 0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'income_tax_expense_benefit_deferred': {'value': -163000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'net_income_loss': {'value': 3373000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'operating_income_loss': {'value': 4502000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'operating_expenses': {'value': 7338000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 3189000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'interest_expense_operating': {'value': 704000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'revenues': {'value': 42440000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}}, 'cash_flow_statement': {'net_cash_flow_from_investing_activities': {'value': -1161000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_financing_activities': {'value': -4026000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities': {'value': 3985000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_operating_activities_continuing': {'value': 3985000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities_continuing': {'value': -1161000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow': {'value': -1202000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_continuing': {'value': -1202000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities_continuing': {'value': -4026000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}}, 'comprehensive_income': {'other_comprehensive_income_loss': {'value': -3592000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss_attributable_to_parent': {'value': 3175000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss': {'value': 3175000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -14000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}}, 'balance_sheet': {'equity_attributable_to_parent': {'value': -6220000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'fixed_assets': {'value': 9716000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_noncontrolling_interest': {'value': 452000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'liabilities': {'value': 115065000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'current_liabilities': {'value': 19511000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'noncurrent_liabilities': {'value': 95554000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'other_than_fixed_noncurrent_assets': {'value': 77664000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'assets': {'value': 109297000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'equity': {'value': -5768000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'noncurrent_assets': {'value': 77664000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'liabilities_and_equity': {'value': 109297000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'current_assets': {'value': 31633000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}}}}, {'id': '0001341439:2022:FY', 'start_date': '2021-06-01', 'end_date': '2022-05-31', 'filing_date': '2022-06-21', 'timeframe': 'annual', 'fiscal_period': 'FY', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-023675', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-22-023675/files/orcl-10k_20220531_htm.xml', 'financials': {'comprehensive_income': {'comprehensive_income_loss_attributable_to_parent': {'value': 6200000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -517000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss': {'value': 6200000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss': {'value': -567000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}}, 'balance_sheet': {'noncurrent_liabilities': {'value': 95554000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'current_liabilities': {'value': 19511000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'other_than_fixed_noncurrent_assets': {'value': 77664000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'equity': {'value': -5768000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'fixed_assets': {'value': 9716000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_noncontrolling_interest': {'value': 452000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'equity_attributable_to_parent': {'value': -6220000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'current_assets': {'value': 31633000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'liabilities': {'value': 115065000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'assets': {'value': 109297000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'liabilities_and_equity': {'value': 109297000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'noncurrent_assets': {'value': 77664000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}}, 'income_statement': {'income_loss_from_continuing_operations_after_tax': {'value': 6901000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'revenues': {'value': 42440000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 184000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'costs_and_expenses': {'value': 31514000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'income_tax_expense_benefit_deferred': {'value': -1146000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'income_tax_expense_benefit_current': {'value': 2078000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Current', 'order': 2300}, 'income_loss_from_continuing_operations_before_tax': {'value': 10926000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_attributable_to_parent': {'value': 6717000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'benefits_costs_expenses': {'value': 31514000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'operating_expenses': {'value': 31514000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'operating_income_loss': {'value': 10926000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 6717000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'income_tax_expense_benefit': {'value': 932000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'basic_earnings_per_share': {'value': 2.49, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss': {'value': 6901000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'interest_expense_operating': {'value': 2755000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'diluted_earnings_per_share': {'value': 2.41, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}}, 'cash_flow_statement': {'net_cash_flow_from_operating_activities_continuing': {'value': 9539000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities': {'value': -29126000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_financing_activities_continuing': {'value': -29126000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_investing_activities_continuing': {'value': 11220000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_investing_activities': {'value': 11220000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities': {'value': 9539000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow': {'value': -8367000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_continuing': {'value': -8367000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}}}}, {'id': '0001341439:2022:Q3', 'start_date': '2021-12-01', 'end_date': '2022-02-28', 'filing_date': '2022-03-11', 'timeframe': 'quarterly', 'fiscal_period': 'Q3', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-22-009859', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-22-009859/files/orcl-10q_20220228_htm.xml', 'financials': {'income_statement': {'benefits_costs_expenses': {'value': 6691000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'operating_expenses': {'value': 6691000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'net_income_loss': {'value': 2319000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'income_loss_from_continuing_operations_before_tax': {'value': 3822000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'income_tax_expense_benefit': {'value': 521000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'diluted_earnings_per_share': {'value': 0.84, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 2319000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'revenues': {'value': 10513000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'costs_and_expenses': {'value': 6691000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'basic_earnings_per_share': {'value': 0.87, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'income_loss_from_continuing_operations_after_tax': {'value': 2319000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'interest_expense_operating': {'value': 667000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'income_tax_expense_benefit_deferred': {'value': -163000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'net_income_loss_attributable_to_parent': {'value': 2319000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'operating_income_loss': {'value': 3822000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}}, 'balance_sheet': {'assets': {'value': 108644000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_liabilities': {'value': 96022000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity_attributable_to_noncontrolling_interest': {'value': 485000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'current_liabilities': {'value': 20833000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'equity_attributable_to_parent': {'value': -8696000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'other_than_fixed_noncurrent_assets': {'value': 76969000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'liabilities': {'value': 116855000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'equity': {'value': -8211000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'liabilities_and_equity': {'value': 108644000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'fixed_assets': {'value': 8609000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'current_assets': {'value': 31675000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'noncurrent_assets': {'value': 76969000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}}, 'comprehensive_income': {'other_comprehensive_income_loss': {'value': 2257000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -62000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss': {'value': 2257000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': 2257000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}}, 'cash_flow_statement': {'net_cash_flow_from_investing_activities_continuing': {'value': 2432000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_financing_activities': {'value': -1579000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_operating_activities': {'value': 3845000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities': {'value': 2432000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_continuing': {'value': 4698000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow': {'value': 4698000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_operating_activities_continuing': {'value': 3845000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_financing_activities_continuing': {'value': -1579000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}}}}, {'id': '0001341439:2022:Q2', 'start_date': '2021-09-01', 'end_date': '2021-11-30', 'filing_date': '2021-12-10', 'timeframe': 'quarterly', 'fiscal_period': 'Q2', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-21-060022', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-21-060022/files/orcl-10q_20211130_htm.xml', 'financials': {'income_statement': {'operating_expenses': {'value': 11184000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'diluted_earnings_per_share': {'value': -0.46, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'net_income_loss_attributable_to_parent': {'value': -1247000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'net_income_loss': {'value': -1247000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'income_loss_from_continuing_operations_before_tax': {'value': -824000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'operating_income_loss': {'value': -824000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'interest_expense_operating': {'value': 679000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'revenues': {'value': 10360000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'income_loss_from_continuing_operations_after_tax': {'value': -1247000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'net_income_loss_available_to_common_stockholders_basic': {'value': -1247000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'costs_and_expenses': {'value': 11184000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'benefits_costs_expenses': {'value': 11184000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'income_tax_expense_benefit_deferred': {'value': -805000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'basic_earnings_per_share': {'value': -0.46, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'income_tax_expense_benefit': {'value': -249000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}}, 'cash_flow_statement': {'net_cash_flow_from_operating_activities_continuing': {'value': -3682000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities_continuing': {'value': 10730000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_financing_activities_continuing': {'value': -12053000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow': {'value': -5005000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_investing_activities': {'value': 10730000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities': {'value': -3682000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_financing_activities': {'value': -12053000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_continuing': {'value': -5005000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}}, 'balance_sheet': {'assets': {'value': 106897000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_assets': {'value': 75819000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'current_assets': {'value': 31078000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'liabilities': {'value': 116555000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'fixed_assets': {'value': 8029000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'equity_attributable_to_noncontrolling_interest': {'value': 443000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'equity': {'value': -9658000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'liabilities_and_equity': {'value': 106897000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'current_liabilities': {'value': 18881000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'other_than_fixed_noncurrent_assets': {'value': 75819000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'noncurrent_liabilities': {'value': 97674000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'equity_attributable_to_parent': {'value': -10101000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}}, 'comprehensive_income': {'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}, 'comprehensive_income_loss_attributable_to_parent': {'value': -1467000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss': {'value': -1467000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -220000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'other_comprehensive_income_loss': {'value': -1467000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}}}}, {'id': '0001341439:2022:Q1', 'start_date': '2021-06-01', 'end_date': '2021-08-31', 'filing_date': '2021-09-13', 'timeframe': 'quarterly', 'fiscal_period': 'Q1', 'fiscal_year': '2022', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'source_filing_url': 'https://api.polygon.io/v1/reference/sec/filings/0001564590-21-047772', 'source_filing_file_url': 'http://api.polygon.io/v1/reference/sec/filings/0001564590-21-047772/files/orcl-10q_20210831_htm.xml', 'financials': {'comprehensive_income': {'other_comprehensive_income_loss': {'value': 2236000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss': {'value': 2236000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': 2236000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'other_comprehensive_income_loss_attributable_to_parent': {'value': -221000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}}, 'balance_sheet': {'equity': {'value': -1130000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'current_assets': {'value': 47117000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity_attributable_to_noncontrolling_interest': {'value': 411000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'other_than_fixed_noncurrent_assets': {'value': 75807000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'current_liabilities': {'value': 23071000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'fixed_assets': {'value': 7610000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'liabilities': {'value': 124054000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'liabilities_and_equity': {'value': 122924000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'assets': {'value': 122924000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_assets': {'value': 75807000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}, 'equity_attributable_to_parent': {'value': -1541000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'noncurrent_liabilities': {'value': 100983000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}}, 'income_statement': {'income_loss_from_continuing_operations_before_tax': {'value': 3427000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'net_income_loss_attributable_to_parent': {'value': 2457000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'diluted_earnings_per_share': {'value': 0.86, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'income_tax_expense_benefit': {'value': 224000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'basic_earnings_per_share': {'value': 0.89, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'income_loss_from_continuing_operations_after_tax': {'value': 2457000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'income_tax_expense_benefit_deferred': {'value': -15000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}, 'net_income_loss': {'value': 2457000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'interest_expense_operating': {'value': 705000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 2457000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'benefits_costs_expenses': {'value': 6301000000.0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'costs_and_expenses': {'value': 6301000000.0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'revenues': {'value': 9728000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'operating_expenses': {'value': 6301000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'operating_income_loss': {'value': 3427000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}}, 'cash_flow_statement': {'net_cash_flow_from_operating_activities': {'value': 5391000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_from_investing_activities': {'value': -781000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_operating_activities_continuing': {'value': 5391000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow_from_investing_activities_continuing': {'value': -781000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow': {'value': -6858000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_continuing': {'value': -6858000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities_continuing': {'value': -11468000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}, 'net_cash_flow_from_financing_activities': {'value': -11468000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}}}}, {'id': '0001341439:2021:Q4', 'start_date': '2021-03-01', 'end_date': '2021-05-31', 'timeframe': 'quarterly', 'fiscal_period': 'Q4', 'fiscal_year': '2021', 'cik': '0001341439', 'sic': '7372', 'tickers': ['ORCL'], 'company_name': 'ORACLE CORP', 'financials': {'comprehensive_income': {'other_comprehensive_income_loss_attributable_to_parent': {'value': -20000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss Attributable To Parent', 'order': 600}, 'other_comprehensive_income_loss': {'value': -9732000000.0, 'unit': 'USD', 'label': 'Other Comprehensive Income/Loss', 'order': 400}, 'comprehensive_income_loss': {'value': 4012000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss', 'order': 100}, 'comprehensive_income_loss_attributable_to_parent': {'value': 4012000000.0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Parent', 'order': 300}, 'comprehensive_income_loss_attributable_to_noncontrolling_interest': {'value': 0, 'unit': 'USD', 'label': 'Comprehensive Income/Loss Attributable To Noncontrolling Interest', 'order': 200}}, 'balance_sheet': {'liabilities': {'value': 125155000000.0, 'unit': 'USD', 'label': 'Liabilities', 'order': 600}, 'noncurrent_liabilities': {'value': 100991000000.0, 'unit': 'USD', 'label': 'Noncurrent Liabilities', 'order': 800}, 'commitments_and_contingencies': {'value': 0, 'unit': 'USD', 'label': 'Commitments and Contingencies', 'order': 900}, 'fixed_assets': {'value': 7049000000.0, 'unit': 'USD', 'label': 'Fixed Assets', 'order': 400}, 'liabilities_and_equity': {'value': 131107000000.0, 'unit': 'USD', 'label': 'Liabilities And Equity', 'order': 1900}, 'current_assets': {'value': 55567000000.0, 'unit': 'USD', 'label': 'Current Assets', 'order': 200}, 'equity_attributable_to_noncontrolling_interest': {'value': 714000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Noncontrolling Interest', 'order': 1500}, 'current_liabilities': {'value': 24164000000.0, 'unit': 'USD', 'label': 'Current Liabilities', 'order': 700}, 'equity_attributable_to_parent': {'value': 5238000000.0, 'unit': 'USD', 'label': 'Equity Attributable To Parent', 'order': 1600}, 'equity': {'value': 5952000000.0, 'unit': 'USD', 'label': 'Equity', 'order': 1400}, 'other_than_fixed_noncurrent_assets': {'value': 75540000000.0, 'unit': 'USD', 'label': 'Other Than Fixed Noncurrent Assets', 'order': 500}, 'assets': {'value': 131107000000.0, 'unit': 'USD', 'label': 'Assets', 'order': 100}, 'noncurrent_assets': {'value': 75540000000.0, 'unit': 'USD', 'label': 'Noncurrent Assets', 'order': 300}}, 'cash_flow_statement': {'net_cash_flow_from_operating_activities': {'value': 4842000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities', 'order': 100}, 'net_cash_flow_continuing': {'value': 7729000000.0, 'unit': 'USD', 'label': 'Net Cash Flow, Continuing', 'order': 1200}, 'net_cash_flow_from_financing_activities': {'value': 6798000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities', 'order': 700}, 'net_cash_flow_from_investing_activities': {'value': -3911000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities', 'order': 400}, 'net_cash_flow_from_investing_activities_continuing': {'value': -3911000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Investing Activities, Continuing', 'order': 500}, 'net_cash_flow_from_operating_activities_continuing': {'value': 4842000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Operating Activities, Continuing', 'order': 200}, 'net_cash_flow': {'value': 7729000000.0, 'unit': 'USD', 'label': 'Net Cash Flow', 'order': 1100}, 'net_cash_flow_from_financing_activities_continuing': {'value': 6798000000.0, 'unit': 'USD', 'label': 'Net Cash Flow From Financing Activities, Continuing', 'order': 800}}, 'income_statement': {'net_income_loss_attributable_to_parent': {'value': 4032000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Parent', 'order': 3500}, 'revenues': {'value': 40479000000.0, 'unit': 'USD', 'label': 'Revenues', 'order': 100}, 'basic_earnings_per_share': {'value': 1.4100000000000001, 'unit': 'USD / shares', 'label': 'Basic Earnings Per Share', 'order': 4200}, 'net_income_loss_available_to_common_stockholders_basic': {'value': 4032000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Available To Common Stockholders, Basic', 'order': 3700}, 'net_income_loss_attributable_to_noncontrolling_interest': {'value': 180000000.0, 'unit': 'USD', 'label': 'Net Income/Loss Attributable To Noncontrolling Interest', 'order': 3300}, 'net_income_loss': {'value': 4212000000.0, 'unit': 'USD', 'label': 'Net Income/Loss', 'order': 3200}, 'benefits_costs_expenses': {'value': 0, 'unit': 'USD', 'label': 'Benefits Costs and Expenses', 'order': 200}, 'preferred_stock_dividends_and_other_adjustments': {'value': 0, 'unit': 'USD', 'label': 'Preferred Stock Dividends And Other Adjustments', 'order': 3900}, 'costs_and_expenses': {'value': 0, 'unit': 'USD', 'label': 'Costs And Expenses', 'order': 600}, 'income_loss_from_continuing_operations_before_tax': {'value': 40479000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations Before Tax', 'order': 1500}, 'income_tax_expense_benefit': {'value': 124000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit', 'order': 2200}, 'income_loss_from_continuing_operations_after_tax': {'value': 40479000000.0, 'unit': 'USD', 'label': 'Income/Loss From Continuing Operations After Tax', 'order': 1400}, 'operating_income_loss': {'value': 4541000000.0, 'unit': 'USD', 'label': 'Operating Income/Loss', 'order': 1100}, 'operating_expenses': {'value': 6686000000.0, 'unit': 'USD', 'label': 'Operating Expenses', 'order': 1000}, 'diluted_earnings_per_share': {'value': 1.3599999999999999, 'unit': 'USD / shares', 'label': 'Diluted Earnings Per Share', 'order': 4300}, 'interest_expense_operating': {'value': 697000000.0, 'unit': 'USD', 'label': 'Interest Expense, Operating', 'order': 2700}, 'participating_securities_distributed_and_undistributed_earnings_loss_basic': {'value': 0, 'unit': 'USD', 'label': 'Participating Securities, Distributed And Undistributed Earnings/Loss, Basic', 'order': 3800}, 'income_tax_expense_benefit_deferred': {'value': 50000000.0, 'unit': 'USD', 'label': 'Income Tax Expense/Benefit, Deferred', 'order': 2400}}}}], 'status': 'OK', 'request_id': '96b927a71f4c8e23055333ab63bdb375', 'next_url': 'https://api.polygon.io/vX/reference/financials?cursor=YXA9MDAwMTM0MTQzOSUzQTIwMjElM0FRNCZhcz0mbGltaXQ9MTAmcGVyaW9kX29mX3JlcG9ydF9kYXRlLmx0ZT0yMDIxLTA1LTMxJnNvcnQ9cGVyaW9kX29mX3JlcG9ydF9kYXRlJnRpY2tlcj1PUkNM'}\n", - "output_value": " 0 1 2 3\n0 Oracle Corp 78558000000.0 234774781919.99997 2.9885534499350794", - "cells_accessed": [[7, 15]], - "array_output": [["Oracle Corp", "78558000000.0", "234774781919.99997", "2.9885534499350794"]], - "formatted_code": "from pprint import pprint\nimport pandas as pd\nimport json\nimport js\n\nsymbol = c(7, 15)\n\nstock_financials = await js.fetch('https://api.polygon.io/vX/reference/financials?ticker={}&apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nstock_financials_json = json.loads(await stock_financials.text())\nprint(stock_financials_json)\nincome_statement = stock_financials_json[\"results\"][0][\"financials\"][\"income_statement\"]\nrevenue = income_statement[\"revenues\"][\"value\"]\n\n\nmarket_data = await js.fetch('https://api.polygon.io/v3/reference/tickers/{}?apiKey=_xBCl_0zcb9H1W25jJEK5pQaQTVLtemL'.format(symbol), {\n \"method\": \"GET\",\n \"headers\": {\"Content-Type\": \"application/json\"}\n})\nmarket_data_json = json.loads(await market_data.text())[\"results\"]\nmarket_cap = market_data_json[\"market_cap\"]\nname = market_data_json[\"name\"]\n\npd.DataFrame([[\n name,\n \"{:}\".format(revenue),\n \"{:}\".format(market_cap),\n \"{:}\".format(market_cap / revenue),\n]])\n", - "error_span": null - }, - "dependent_cells": [[7, 15]] - }, - { "x": 9, "y": 4, "type": "TEXT", "value": "Revenue", "last_modified": "2023-02-17T00:48:19.048Z" }, - { "x": 9, "y": 6, "type": "COMPUTED", "value": "1860421000.0", "last_modified": "2023-03-21T19:54:12.884Z" }, - { "x": 9, "y": 7, "type": "COMPUTED", "value": "17606000000.0", "last_modified": "2023-03-21T19:54:22.347Z" }, - { "x": 9, "y": 8, "type": "COMPUTED", "value": "1675100000.0", "last_modified": "2023-03-21T19:54:26.458Z" }, - { "x": 9, "y": 9, "type": "COMPUTED", "value": "3194208000.0", "last_modified": "2023-03-21T19:54:33.553Z" }, - { "x": 9, "y": 10, "type": "COMPUTED", "value": "1505118000.0", "last_modified": "2023-03-21T19:55:12.638Z" }, - { "x": 9, "y": 11, "type": "COMPUTED", "value": "299014000.0", "last_modified": "2023-03-21T19:55:18.010Z" }, - { "x": 9, "y": 12, "type": "COMPUTED", "value": "1858000000.0", "last_modified": "2023-03-21T19:57:07.476Z" }, - { "x": 9, "y": 13, "type": "COMPUTED", "value": "78558000000.0", "last_modified": "2023-03-21T19:55:01.055Z" }, - { "x": 9, "y": 14, "type": "COMPUTED", "value": "576322000.0", "last_modified": "2023-03-21T19:55:05.226Z" }, - { "x": 9, "y": 15, "type": "COMPUTED", "value": "78558000000.0", "last_modified": "2023-03-21T19:55:08.809Z" }, - { "x": 10, "y": 4, "type": "TEXT", "value": "Market cap", "last_modified": "2023-02-17T00:48:24.560Z" }, - { "x": 10, "y": 6, "type": "COMPUTED", "value": "43567152000.0", "last_modified": "2023-03-21T19:54:12.884Z" }, - { - "x": 10, - "y": 7, - "type": "COMPUTED", - "value": "166407958362.24", - "last_modified": "2023-03-21T19:54:22.347Z" - }, - { - "x": 10, - "y": 8, - "type": "COMPUTED", - "value": "21180114934.109997", - "last_modified": "2023-03-21T19:54:26.458Z" - }, - { "x": 10, "y": 9, "type": "COMPUTED", "value": "17392936523.04", "last_modified": "2023-03-21T19:54:33.553Z" }, - { "x": 10, "y": 10, "type": "COMPUTED", "value": "4563793430.91", "last_modified": "2023-03-21T19:55:12.638Z" }, - { "x": 10, "y": 11, "type": "COMPUTED", "value": "420066786.56", "last_modified": "2023-03-21T19:55:18.010Z" }, - { - "x": 10, - "y": 12, - "type": "COMPUTED", - "value": "13586885367.119999", - "last_modified": "2023-03-21T19:57:07.476Z" - }, - { - "x": 10, - "y": 13, - "type": "COMPUTED", - "value": "234774781919.99997", - "last_modified": "2023-03-21T19:55:01.055Z" - }, - { "x": 10, "y": 14, "type": "COMPUTED", "value": "3365348452.44", "last_modified": "2023-03-21T19:55:05.226Z" }, - { - "x": 10, - "y": 15, - "type": "COMPUTED", - "value": "234774781919.99997", - "last_modified": "2023-03-21T19:55:08.809Z" - }, - { "x": 11, "y": 4, "type": "TEXT", "value": "Multiple", "last_modified": "2023-02-17T00:48:28.058Z" }, - { - "x": 11, - "y": 6, - "type": "COMPUTED", - "value": "23.41789949694182", - "last_modified": "2023-03-21T19:54:12.884Z" - }, - { - "x": 11, - "y": 7, - "type": "COMPUTED", - "value": "9.45177543804612", - "last_modified": "2023-03-21T19:54:22.347Z" - }, - { - "x": 11, - "y": 8, - "type": "COMPUTED", - "value": "12.644089865745327", - "last_modified": "2023-03-21T19:54:26.458Z" - }, - { - "x": 11, - "y": 9, - "type": "COMPUTED", - "value": "5.4451483820214595", - "last_modified": "2023-03-21T19:54:33.553Z" - }, - { - "x": 11, - "y": 10, - "type": "COMPUTED", - "value": "3.0321831450490926", - "last_modified": "2023-03-21T19:55:12.638Z" - }, - { - "x": 11, - "y": 11, - "type": "COMPUTED", - "value": "1.4048398622138094", - "last_modified": "2023-03-21T19:55:18.010Z" - }, - { - "x": 11, - "y": 12, - "type": "COMPUTED", - "value": "7.312640133003229", - "last_modified": "2023-03-21T19:57:07.476Z" - }, - { - "x": 11, - "y": 13, - "type": "COMPUTED", - "value": "2.9885534499350794", - "last_modified": "2023-03-21T19:55:01.055Z" - }, - { - "x": 11, - "y": 14, - "type": "COMPUTED", - "value": "5.839354479683233", - "last_modified": "2023-03-21T19:55:05.226Z" - }, - { - "x": 11, - "y": 15, - "type": "COMPUTED", - "value": "2.9885534499350794", - "last_modified": "2023-03-21T19:55:08.809Z" - }, - { "x": 13, "y": 2, "type": "TEXT", "value": "Analysis", "last_modified": "2022-05-11T16:48:26.882Z" }, - { "x": 13, "y": 4, "type": "TEXT", "value": "Implied cap", "last_modified": "2022-05-14T15:37:51.315Z" }, - { - "x": 13, - "y": 6, - "type": "PYTHON", - "value": "2154446753", - "python_code": "from decimal import Decimal\n\nresult = []\n\nfor i in range(0, 10):\n val = c(11, 6 + i) / c(5, 6 + i) * Decimal((await c(4, 6 + i)).value)\n result.append(int(val))\n\nresult", - "last_modified": "2023-03-21T19:57:13.349Z", - "python_output": "", - "array_cells": [ - [13, 6], - [13, 7], - [13, 8], - [13, 9], - [13, 10], - [13, 11], - [13, 12], - [13, 13], - [13, 14], - [13, 15] - ], - "dependent_cells": [ - [11, 6], - [5, 6], - [4, 6], - [11, 7], - [5, 7], - [4, 7], - [11, 8], - [5, 8], - [4, 8], - [11, 9], - [5, 9], - [4, 9], - [11, 10], - [5, 10], - [4, 10], - [11, 11], - [5, 11], - [4, 11], - [11, 12], - [5, 12], - [4, 12], - [11, 13], - [5, 13], - [4, 13], - [11, 14], - [5, 14], - [4, 14], - [11, 15], - [5, 15], - [4, 15] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "[2154446753, 482040547, 10279645060, 4356118705, 485149303, 92719430, 343694086, 448283017, 689043828, 328740879]", - "cells_accessed": [ - [11, 6], - [5, 6], - [4, 6], - [11, 7], - [5, 7], - [4, 7], - [11, 8], - [5, 8], - [4, 8], - [11, 9], - [5, 9], - [4, 9], - [11, 10], - [5, 10], - [4, 10], - [11, 11], - [5, 11], - [4, 11], - [11, 12], - [5, 12], - [4, 12], - [11, 13], - [5, 13], - [4, 13], - [11, 14], - [5, 14], - [4, 14], - [11, 15], - [5, 15], - [4, 15] - ], - "array_output": [ - 2154446753, 482040547, 10279645060, 4356118705, 485149303, 92719430, 343694086, 448283017, 689043828, - 328740879 - ], - "formatted_code": "from decimal import Decimal\n\nresult = []\n\nfor i in range(0, 10):\n val = c(11, 6 + i) / c(5, 6 + i) * Decimal((await c(4, 6 + i)).value)\n result.append(int(val))\n\nresult\n", - "error_span": null - } - }, - { "x": 13, "y": 7, "type": "COMPUTED", "value": "482040547", "last_modified": "2023-03-21T19:57:13.349Z" }, - { "x": 13, "y": 8, "type": "COMPUTED", "value": "10279645060", "last_modified": "2023-03-21T19:57:13.349Z" }, - { "x": 13, "y": 9, "type": "COMPUTED", "value": "4356118705", "last_modified": "2023-03-21T19:57:13.349Z" }, - { "x": 13, "y": 10, "type": "COMPUTED", "value": "485149303", "last_modified": "2023-03-21T19:57:13.349Z" }, - { "x": 13, "y": 11, "type": "COMPUTED", "value": "92719430", "last_modified": "2023-03-21T19:57:13.349Z" }, - { "x": 13, "y": 12, "type": "COMPUTED", "value": "343694086", "last_modified": "2023-03-21T19:57:13.349Z" }, - { "x": 13, "y": 13, "type": "COMPUTED", "value": "448283017", "last_modified": "2023-03-21T19:57:13.349Z" }, - { "x": 13, "y": 14, "type": "COMPUTED", "value": "689043828", "last_modified": "2023-03-21T19:57:13.349Z" }, - { "x": 13, "y": 15, "type": "COMPUTED", "value": "328740879", "last_modified": "2023-03-21T19:57:13.349Z" }, - { "x": 14, "y": 4, "type": "TEXT", "value": "Valuation", "last_modified": "2022-05-14T15:37:58.886Z" }, - { - "x": 14, - "y": 6, - "type": "PYTHON", - "value": "1958590", - "python_code": "from decimal import Decimal\n\nresult = []\n\nfor i in range(0, 10):\n val = c(15, 6 + i) * c(1, 6 + i)\n result.append(int(val))\n\nresult", - "last_modified": "2023-03-21T19:57:26.989Z", - "python_output": "", - "array_cells": [ - [14, 6], - [14, 7], - [14, 8], - [14, 9], - [14, 10], - [14, 11], - [14, 12], - [14, 13], - [14, 14], - [14, 15] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "[1958590, 385632, 6221891, 64060575, 1905948, 138385, 2230077, 2241420, 2296815, 4551804]", - "cells_accessed": [ - [15, 6], - [1, 6], - [15, 7], - [1, 7], - [15, 8], - [1, 8], - [15, 9], - [1, 9], - [15, 10], - [1, 10], - [15, 11], - [1, 11], - [15, 12], - [1, 12], - [15, 13], - [1, 13], - [15, 14], - [1, 14], - [15, 15], - [1, 15] - ], - "array_output": [1958590, 385632, 6221891, 64060575, 1905948, 138385, 2230077, 2241420, 2296815, 4551804], - "formatted_code": "from decimal import Decimal\n\nresult = []\n\nfor i in range(0, 10):\n val = c(15, 6 + i) * c(1, 6 + i)\n result.append(int(val))\n\nresult\n", - "error_span": null - }, - "dependent_cells": [ - [15, 6], - [1, 6] - ] - }, - { "x": 14, "y": 7, "type": "COMPUTED", "value": "385632", "last_modified": "2023-03-21T19:57:26.989Z" }, - { "x": 14, "y": 8, "type": "COMPUTED", "value": "6221891", "last_modified": "2023-03-21T19:57:26.989Z" }, - { "x": 14, "y": 9, "type": "COMPUTED", "value": "64060575", "last_modified": "2023-03-21T19:57:26.989Z" }, - { "x": 14, "y": 10, "type": "COMPUTED", "value": "1905948", "last_modified": "2023-03-21T19:57:26.989Z" }, - { "x": 14, "y": 11, "type": "COMPUTED", "value": "138385", "last_modified": "2023-03-21T19:57:26.989Z" }, - { "x": 14, "y": 12, "type": "COMPUTED", "value": "2230077", "last_modified": "2023-03-21T19:57:26.989Z" }, - { "x": 14, "y": 13, "type": "COMPUTED", "value": "2241420", "last_modified": "2023-03-21T19:57:26.989Z" }, - { "x": 14, "y": 14, "type": "COMPUTED", "value": "2296815", "last_modified": "2023-03-21T19:57:26.989Z" }, - { "x": 14, "y": 15, "type": "COMPUTED", "value": "4551804", "last_modified": "2023-03-21T19:57:26.989Z" }, - { "x": 15, "y": 4, "type": "TEXT", "value": "Return multiple", "last_modified": "2022-05-11T16:46:47.007Z" }, - { - "x": 15, - "y": 6, - "type": "PYTHON", - "value": "0.195859", - "python_code": "result = []\n\nfor i in range(0, 10):\n result.append(\n \"{:,.6f}\".format(c(13, 6 + i) / c(4, 6 + i))\n )\n\nresult", - "last_modified": "2023-03-21T19:57:26.793Z", - "python_output": "", - "array_cells": [ - [15, 6], - [15, 7], - [15, 8], - [15, 9], - [15, 10], - [15, 11], - [15, 12], - [15, 13], - [15, 14], - [15, 15] - ], - "dependent_cells": [ - [13, 6], - [4, 6], - [13, 7], - [4, 7], - [13, 8], - [4, 8], - [13, 9], - [4, 9], - [13, 10], - [4, 10], - [13, 11], - [4, 11], - [13, 12], - [4, 12], - [13, 13], - [4, 13], - [13, 14], - [4, 14], - [13, 15], - [4, 15] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "['0.195859', '0.048204', '0.270517', '4.270705', '0.086634', '0.027677', '0.131181', '0.224142', '0.459363', '0.252878']", - "cells_accessed": [ - [13, 6], - [4, 6], - [13, 7], - [4, 7], - [13, 8], - [4, 8], - [13, 9], - [4, 9], - [13, 10], - [4, 10], - [13, 11], - [4, 11], - [13, 12], - [4, 12], - [13, 13], - [4, 13], - [13, 14], - [4, 14], - [13, 15], - [4, 15] - ], - "array_output": [ - "0.195859", - "0.048204", - "0.270517", - "4.270705", - "0.086634", - "0.027677", - "0.131181", - "0.224142", - "0.459363", - "0.252878" - ], - "formatted_code": "result = []\n\nfor i in range(0, 10):\n result.append(\n \"{:,.6f}\".format(c(13, 6 + i) / c(4, 6 + i))\n )\n\nresult\n", - "error_span": null - } - }, - { "x": 15, "y": 7, "type": "COMPUTED", "value": "0.048204", "last_modified": "2023-03-21T19:57:26.793Z" }, - { "x": 15, "y": 8, "type": "COMPUTED", "value": "0.270517", "last_modified": "2023-03-21T19:57:26.793Z" }, - { "x": 15, "y": 9, "type": "COMPUTED", "value": "4.270705", "last_modified": "2023-03-21T19:57:26.793Z" }, - { "x": 15, "y": 10, "type": "COMPUTED", "value": "0.086634", "last_modified": "2023-03-21T19:57:26.793Z" }, - { "x": 15, "y": 11, "type": "COMPUTED", "value": "0.027677", "last_modified": "2023-03-21T19:57:26.793Z" }, - { "x": 15, "y": 12, "type": "COMPUTED", "value": "0.131181", "last_modified": "2023-03-21T19:57:26.793Z" }, - { "x": 15, "y": 13, "type": "COMPUTED", "value": "0.224142", "last_modified": "2023-03-21T19:57:26.793Z" }, - { "x": 15, "y": 14, "type": "COMPUTED", "value": "0.459363", "last_modified": "2023-03-21T19:57:26.793Z" }, - { "x": 15, "y": 15, "type": "COMPUTED", "value": "0.252878", "last_modified": "2023-03-21T19:57:26.793Z" }, - { "x": 17, "y": 2, "type": "TEXT", "value": "Portfolio summary", "last_modified": "2022-05-14T15:43:00.889Z" }, - { "x": 17, "y": 5, "type": "TEXT", "value": "CAPITAL INVESTED", "last_modified": "2023-02-17T00:40:08.566Z" }, - { - "x": 19, - "y": 5, - "type": "PYTHON", - "value": "133000000", - "python_code": "c(1, 18)\n", - "last_modified": "2023-03-14T17:27:40.744Z", - "python_output": "", - "array_cells": [], - "dependent_cells": [[1, 18]], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "133000000", - "cells_accessed": [[1, 18]], - "formatted_code": "c(1, 18)\n", - "error_span": null - } - }, - { "x": 17, "y": 7, "type": "TEXT", "value": "Average", "last_modified": "2023-02-17T00:40:08.592Z" }, - { "x": 17, "y": 8, "type": "TEXT", "value": "ENTRY VALUATION", "last_modified": "2023-02-17T00:40:08.592Z" }, - { - "x": 19, - "y": 8, - "type": "PYTHON", - "value": "7639000000.0", - "python_code": "df = getCells((4, 6), (4, 15))\n\ndf = df.astype(float)\n\ndf[0].mean()\n", - "last_modified": "2023-02-17T00:51:05.155Z", - "python_output": "", - "array_cells": [], - "dependent_cells": [ - [4, 6], - [4, 7], - [4, 8], - [4, 9], - [4, 10], - [4, 11], - [4, 12], - [4, 13], - [4, 14], - [4, 15] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "7639000000.0", - "cells_accessed": [ - [4, 6], - [4, 7], - [4, 8], - [4, 9], - [4, 10], - [4, 11], - [4, 12], - [4, 13], - [4, 14], - [4, 15] - ], - "formatted_code": "df = getCells((4, 6), (4, 15))\n\ndf = df.astype(float)\n\ndf[0].mean()\n", - "error_span": null - } - }, - { - "x": 17, - "y": 9, - "type": "TEXT", - "value": "ENTRY REVENUE MULTIPLE", - "last_modified": "2023-02-17T00:40:08.635Z" - }, - { - "x": 19, - "y": 9, - "type": "PYTHON", - "value": "54.30247523354619", - "python_code": "df = getCells((5, 6), (5, 15))\n\ndf = df.astype(float)\n\ndf[0].mean()\n", - "last_modified": "2023-03-21T19:54:06.258Z", - "python_output": "", - "array_cells": [], - "dependent_cells": [ - [5, 6], - [5, 7], - [5, 8], - [5, 9], - [5, 10], - [5, 11], - [5, 12], - [5, 13], - [5, 14], - [5, 15] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "54.30247523354619", - "cells_accessed": [ - [5, 6], - [5, 7], - [5, 8], - [5, 9], - [5, 10], - [5, 11], - [5, 12], - [5, 13], - [5, 14], - [5, 15] - ], - "formatted_code": "df = getCells((5, 6), (5, 15))\n\ndf = df.astype(float)\n\ndf[0].mean()\n", - "error_span": null - } - }, - { "x": 17, "y": 11, "type": "TEXT", "value": "CURRENT VALUATION", "last_modified": "2023-02-17T00:40:08.675Z" }, - { - "x": 19, - "y": 11, - "type": "PYTHON", - "value": "8599113.7", - "python_code": "df = getCells((14, 6), (14, 15))\n\ndf = df.astype(float)\n\ndf[0].mean()\n", - "last_modified": "2023-03-21T19:57:27.074Z", - "python_output": "", - "array_cells": [], - "dependent_cells": [ - [14, 6], - [14, 7], - [14, 8], - [14, 9], - [14, 10], - [14, 11], - [14, 12], - [14, 13], - [14, 14], - [14, 15] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "8599113.7", - "cells_accessed": [ - [14, 6], - [14, 7], - [14, 8], - [14, 9], - [14, 10], - [14, 11], - [14, 12], - [14, 13], - [14, 14], - [14, 15] - ], - "formatted_code": "df = getCells((14, 6), (14, 15))\n\ndf = df.astype(float)\n\ndf[0].mean()\n", - "error_span": null - } - }, - { - "x": 17, - "y": 12, - "type": "TEXT", - "value": "CURRENT REVENUE MULTIPLE", - "last_modified": "2023-02-17T00:40:08.718Z" - }, - { - "x": 19, - "y": 12, - "type": "PYTHON", - "value": "0.596716", - "python_code": "df = getCells((15, 6), (15, 15))\n\ndf = df.astype(float)\n\ndf[0].mean()\n", - "last_modified": "2023-03-21T19:57:26.841Z", - "python_output": "", - "array_cells": [], - "dependent_cells": [ - [15, 6], - [15, 7], - [15, 8], - [15, 9], - [15, 10], - [15, 11], - [15, 12], - [15, 13], - [15, 14], - [15, 15] - ], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "0.596716", - "cells_accessed": [ - [15, 6], - [15, 7], - [15, 8], - [15, 9], - [15, 10], - [15, 11], - [15, 12], - [15, 13], - [15, 14], - [15, 15] - ], - "formatted_code": "df = getCells((15, 6), (15, 15))\n\ndf = df.astype(float)\n\ndf[0].mean()\n", - "error_span": null - } - }, - { "x": 17, "y": 14, "type": "TEXT", "value": "TVPI", "last_modified": "2023-02-17T00:40:08.759Z" }, - { - "x": 19, - "y": 14, - "type": "PYTHON", - "value": "0.5967159999999999", - "python_code": "c(15, 18)\n", - "last_modified": "2023-03-21T19:57:27.032Z", - "python_output": "", - "array_cells": [], - "dependent_cells": [[15, 18]], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "0.5967159999999999", - "cells_accessed": [[15, 18]], - "formatted_code": "c(15, 18)\n", - "error_span": null - } - }, - { "x": 17, "y": 15, "type": "TEXT", "value": "IRR", "last_modified": "2023-02-17T00:40:08.796Z" }, - { - "x": 19, - "y": 15, - "type": "PYTHON", - "value": "45.12%", - "python_code": "\"45.12%\"\n", - "last_modified": "2023-02-17T00:51:20.963Z", - "python_output": "", - "array_cells": [], - "dependent_cells": [], - "evaluation_result": { - "success": true, - "std_out": "", - "output_value": "45.12%", - "cells_accessed": [], - "formatted_code": "\"45.12%\"\n", - "error_span": null - } - }, - { "x": 20, "y": 14, "type": "TEXT", "value": " ", "last_modified": "2023-02-17T00:51:53.222Z" }, - { - "x": 1, - "y": 18, - "type": "FORMULA", - "value": "133000000", - "formula_code": "SUM(B6:B15)", - "evaluation_result": { - "success": true, - "output_value": "133000000", - "cells_accessed": [ - [1, 15], - [1, 11], - [1, 10], - [1, 12], - [1, 13], - [1, 6], - [1, 8], - [1, 7], - [1, 9], - [1, 14] - ], - "array_output": [], - "formatted_code": "SUM(B6:B15)", - "error_span": null - }, - "array_cells": [], - "dependent_cells": [ - [1, 15], - [1, 11], - [1, 10], - [1, 12], - [1, 13], - [1, 6], - [1, 8], - [1, 7], - [1, 9], - [1, 14] - ], - "last_modified": "2023-03-14T17:27:40.707Z" - }, - { - "x": 3, - "y": 18, - "type": "FORMULA", - "value": "2407000000", - "formula_code": "SUM(D6:D15)", - "evaluation_result": { - "success": true, - "output_value": "2407000000", - "cells_accessed": [ - [3, 8], - [3, 9], - [3, 12], - [3, 13], - [3, 11], - [3, 7], - [3, 6], - [3, 15], - [3, 14], - [3, 10] - ], - "array_output": [], - "formatted_code": "SUM(D6:D15)", - "error_span": null - }, - "array_cells": [], - "dependent_cells": [ - [3, 8], - [3, 9], - [3, 12], - [3, 13], - [3, 11], - [3, 7], - [3, 6], - [3, 15], - [3, 14], - [3, 10] - ], - "last_modified": "2023-03-14T17:27:46.107Z" - }, - { - "x": 4, - "y": 18, - "type": "FORMULA", - "value": "76390000000", - "formula_code": "SUM(E6:E15)", - "evaluation_result": { - "success": true, - "output_value": "76390000000", - "cells_accessed": [ - [4, 6], - [4, 7], - [4, 9], - [4, 14], - [4, 10], - [4, 12], - [4, 8], - [4, 11], - [4, 13], - [4, 15] - ], - "array_output": [], - "formatted_code": "SUM(E6:E15)", - "error_span": null - }, - "array_cells": [], - "dependent_cells": [ - [4, 6], - [4, 7], - [4, 9], - [4, 14], - [4, 10], - [4, 12], - [4, 8], - [4, 11], - [4, 13], - [4, 15] - ], - "last_modified": "2023-03-14T17:27:50.840Z" - }, - { - "x": 5, - "y": 18, - "type": "FORMULA", - "value": "54.30247523354619", - "formula_code": "AVERAGE(F6:F15)", - "evaluation_result": { - "success": true, - "output_value": "54.30247523354619", - "cells_accessed": [ - [5, 6], - [5, 11], - [5, 15], - [5, 7], - [5, 8], - [5, 12], - [5, 10], - [5, 14], - [5, 9], - [5, 13] - ], - "array_output": [], - "formatted_code": "AVERAGE(F6:F15)", - "error_span": null - }, - "array_cells": [], - "dependent_cells": [ - [5, 6], - [5, 11], - [5, 15], - [5, 7], - [5, 8], - [5, 12], - [5, 10], - [5, 14], - [5, 9], - [5, 13] - ], - "last_modified": "2023-03-21T19:54:06.497Z" - }, - { - "x": 11, - "y": 18, - "type": "FORMULA", - "value": "7.452503770257425", - "formula_code": "AVERAGE(L6:L15)", - "evaluation_result": { - "success": true, - "output_value": "7.452503770257425", - "cells_accessed": [ - [11, 6], - [11, 11], - [11, 8], - [11, 14], - [11, 13], - [11, 12], - [11, 7], - [11, 9], - [11, 10], - [11, 15] - ], - "array_output": [], - "formatted_code": "AVERAGE(L6:L15)", - "error_span": null - }, - "array_cells": [], - "dependent_cells": [ - [11, 6], - [11, 11], - [11, 8], - [11, 14], - [11, 13], - [11, 12], - [11, 7], - [11, 9], - [11, 10], - [11, 15] - ], - "last_modified": "2023-03-21T19:57:07.685Z" - }, - { - "x": 13, - "y": 18, - "type": "FORMULA", - "value": "19659881608", - "formula_code": "SUM(N6:N15)", - "evaluation_result": { - "success": true, - "output_value": "19659881608", - "cells_accessed": [ - [13, 7], - [13, 14], - [13, 15], - [13, 8], - [13, 13], - [13, 11], - [13, 6], - [13, 9], - [13, 12], - [13, 10] - ], - "array_output": [], - "formatted_code": "SUM(N6:N15)", - "error_span": null - }, - "array_cells": [], - "dependent_cells": [ - [13, 7], - [13, 14], - [13, 15], - [13, 8], - [13, 13], - [13, 11], - [13, 6], - [13, 9], - [13, 12], - [13, 10] - ], - "last_modified": "2023-03-21T19:57:13.497Z" - }, - { - "x": 14, - "y": 18, - "type": "FORMULA", - "value": "85991137", - "formula_code": "SUM(O6:O15)", - "evaluation_result": { - "success": true, - "output_value": "85991137", - "cells_accessed": [ - [14, 10], - [14, 15], - [14, 12], - [14, 8], - [14, 14], - [14, 13], - [14, 7], - [14, 9], - [14, 11], - [14, 6] - ], - "array_output": [], - "formatted_code": "SUM(O6:O15)", - "error_span": null - }, - "array_cells": [], - "dependent_cells": [ - [14, 10], - [14, 15], - [14, 12], - [14, 8], - [14, 14], - [14, 13], - [14, 7], - [14, 9], - [14, 11], - [14, 6] - ], - "last_modified": "2023-03-21T19:57:27.074Z" - }, - { - "x": 15, - "y": 18, - "type": "FORMULA", - "value": "0.5967159999999999", - "formula_code": "AVERAGE(P6:P15)", - "evaluation_result": { - "success": true, - "output_value": "0.5967159999999999", - "cells_accessed": [ - [15, 10], - [15, 8], - [15, 6], - [15, 7], - [15, 11], - [15, 15], - [15, 9], - [15, 12], - [15, 13], - [15, 14] - ], - "array_output": [], - "formatted_code": "AVERAGE(P6:P15)", - "error_span": null - }, - "array_cells": [], - "dependent_cells": [ - [15, 10], - [15, 8], - [15, 6], - [15, 7], - [15, 11], - [15, 15], - [15, 9], - [15, 12], - [15, 13], - [15, 14] - ], - "last_modified": "2023-03-21T19:57:26.841Z" - }, - { "x": 1, "y": 19, "type": "TEXT", "value": "TOTAL", "last_modified": "2023-02-21T23:55:50.005Z" }, - { "x": 5, "y": 19, "type": "TEXT", "value": "AVERAGE", "last_modified": "2023-02-21T23:55:50.005Z" }, - { "x": 11, "y": 19, "type": "TEXT", "value": "AVERAGE", "last_modified": "2023-02-21T23:55:50.005Z" }, - { "x": 13, "y": 19, "type": "TEXT", "value": "TOTAL", "last_modified": "2023-02-21T23:55:50.005Z" }, - { "x": 15, "y": 19, "type": "TEXT", "value": "AVERAGE", "last_modified": "2023-02-21T23:55:50.005Z" } - ], - "formats": [ - { "x": 0, "y": 0, "fillColor": "rgb(175, 208, 231)", "bold": true }, - { "x": 0, "y": 2, "fillColor": "rgb(218, 240, 255)", "bold": true }, - { "x": 0, "y": 4, "bold": true }, - { "x": 0, "y": 6, "fillColor": "rgb(216, 255, 232)" }, - { "x": 0, "y": 7, "fillColor": "rgb(216, 255, 232)" }, - { "x": 0, "y": 8, "fillColor": "rgb(216, 255, 232)" }, - { "x": 0, "y": 9, "fillColor": "rgb(216, 255, 232)" }, - { "x": 0, "y": 10, "fillColor": "rgb(216, 255, 232)" }, - { "x": 0, "y": 11, "fillColor": "rgb(216, 255, 232)" }, - { "x": 0, "y": 12, "fillColor": "rgb(216, 255, 232)" }, - { "x": 0, "y": 13, "fillColor": "rgb(216, 255, 232)" }, - { "x": 0, "y": 14, "fillColor": "rgb(216, 255, 232)" }, - { "x": 0, "y": 15, "fillColor": "rgb(216, 255, 232)" }, - { "x": 1, "y": 4, "bold": true }, - { - "x": 1, - "y": 6, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 1, - "y": 7, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 1, - "y": 8, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 1, - "y": 9, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 1, - "y": 10, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 1, - "y": 11, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 1, - "y": 12, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 1, - "y": 13, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 1, - "y": 14, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 1, - "y": 15, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 2, "y": 4, "bold": true }, - { "x": 2, "y": 6, "fillColor": "rgb(216, 255, 232)" }, - { "x": 2, "y": 7, "fillColor": "rgb(216, 255, 232)" }, - { "x": 2, "y": 8, "fillColor": "rgb(216, 255, 232)" }, - { "x": 2, "y": 9, "fillColor": "rgb(216, 255, 232)" }, - { "x": 2, "y": 10, "fillColor": "rgb(216, 255, 232)" }, - { "x": 2, "y": 11, "fillColor": "rgb(216, 255, 232)" }, - { "x": 2, "y": 12, "fillColor": "rgb(216, 255, 232)" }, - { "x": 2, "y": 13, "fillColor": "rgb(216, 255, 232)" }, - { "x": 2, "y": 14, "fillColor": "rgb(216, 255, 232)" }, - { "x": 2, "y": 15, "fillColor": "rgb(216, 255, 232)" }, - { "x": 3, "y": 4, "bold": true }, - { - "x": 3, - "y": 6, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 3, - "y": 7, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 3, - "y": 8, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 3, - "y": 9, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 3, - "y": 10, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 3, - "y": 11, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 3, - "y": 12, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 3, - "y": 13, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 3, - "y": 14, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 3, - "y": 15, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 4, "y": 4, "bold": true }, - { - "x": 4, - "y": 6, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 4, - "y": 7, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 4, - "y": 8, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 4, - "y": 9, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 4, - "y": 10, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 4, - "y": 11, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 4, - "y": 12, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 4, - "y": 13, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 4, - "y": 14, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 4, - "y": 15, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 5, "y": 4, "bold": true }, - { "x": 5, "y": 6, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 5, "y": 7, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 5, "y": 8, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 5, "y": 9, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 5, "y": 10, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 5, "y": 11, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 5, "y": 12, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 5, "y": 13, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 5, "y": 14, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 5, "y": 15, "fillColor": "rgb(216, 255, 232)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 7, "y": 2, "bold": true, "fillColor": "rgb(218, 240, 255)" }, - { "x": 7, "y": 4, "bold": true }, - { "x": 7, "y": 6, "fillColor": "rgb(216, 255, 232)" }, - { "x": 7, "y": 7, "fillColor": "rgb(216, 255, 232)" }, - { "x": 7, "y": 8, "fillColor": "rgb(216, 255, 232)" }, - { "x": 7, "y": 9, "fillColor": "rgb(216, 255, 232)" }, - { "x": 7, "y": 10, "fillColor": "rgb(216, 255, 232)" }, - { "x": 7, "y": 11, "fillColor": "rgb(216, 255, 232)" }, - { "x": 7, "y": 12, "fillColor": "rgb(216, 255, 232)" }, - { "x": 7, "y": 13, "fillColor": "rgb(216, 255, 232)" }, - { "x": 7, "y": 14, "fillColor": "rgb(216, 255, 232)" }, - { "x": 7, "y": 15, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 4, "bold": true }, - { "x": 8, "y": 6, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 7, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 8, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 9, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 10, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 11, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 12, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 13, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 14, "fillColor": "rgb(216, 255, 232)" }, - { "x": 8, "y": 15, "fillColor": "rgb(216, 255, 232)" }, - { "x": 9, "y": 4, "bold": true }, - { - "x": 9, - "y": 6, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 9, - "y": 7, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 9, - "y": 8, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 9, - "y": 9, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 9, - "y": 10, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 9, - "y": 11, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 9, - "y": 12, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 9, - "y": 13, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 9, - "y": 14, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 9, - "y": 15, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 10, "y": 4, "bold": true }, - { - "x": 10, - "y": 6, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 10, - "y": 7, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 10, - "y": 8, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 10, - "y": 9, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 10, - "y": 10, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 10, - "y": 11, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 10, - "y": 12, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 10, - "y": 13, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 10, - "y": 14, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 10, - "y": 15, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 11, "y": 4, "bold": true }, - { - "x": 11, - "y": 6, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 11, - "y": 7, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 11, - "y": 8, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 11, - "y": 9, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 11, - "y": 10, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 11, - "y": 11, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 11, - "y": 12, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 11, - "y": 13, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 11, - "y": 14, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 11, - "y": 15, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { "x": 13, "y": 2, "bold": true, "fillColor": "rgb(218, 240, 255)" }, - { "x": 13, "y": 4, "bold": true }, - { - "x": 13, - "y": 6, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 13, - "y": 7, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 13, - "y": 8, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 13, - "y": 9, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 13, - "y": 10, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 13, - "y": 11, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 13, - "y": 12, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 13, - "y": 13, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 13, - "y": 14, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 13, - "y": 15, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 14, "y": 4, "bold": true }, - { - "x": 14, - "y": 6, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 14, - "y": 7, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 14, - "y": 8, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 14, - "y": 9, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 14, - "y": 10, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 14, - "y": 11, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 14, - "y": 12, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 14, - "y": 13, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 14, - "y": 14, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { - "x": 14, - "y": 15, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 15, "y": 4, "bold": true }, - { - "x": 15, - "y": 6, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 15, - "y": 7, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 15, - "y": 8, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 15, - "y": 9, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 15, - "y": 10, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 15, - "y": 11, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 15, - "y": 12, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 15, - "y": 13, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 15, - "y": 14, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { - "x": 15, - "y": 15, - "fillColor": "rgb(216, 255, 232)", - "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, - "italic": true - }, - { "x": 17, "y": 2, "bold": true, "fillColor": "rgb(218, 240, 255)" }, - { "x": 17, "y": 5, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { - "x": 19, - "y": 5, - "fillColor": "rgb(255, 243, 193)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 17, "y": 7, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { "x": 17, "y": 8, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { - "x": 19, - "y": 8, - "fillColor": "rgb(255, 243, 193)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 17, "y": 9, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { "x": 19, "y": 9, "fillColor": "rgb(255, 243, 193)", "textFormat": { "type": "NUMBER", "decimalPlaces": 2 } }, - { "x": 17, "y": 11, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { - "x": 19, - "y": 11, - "fillColor": "rgb(255, 243, 193)", - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 } - }, - { "x": 17, "y": 12, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { "x": 19, "y": 12, "fillColor": "rgb(255, 243, 193)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 17, "y": 14, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { "x": 19, "y": 14, "fillColor": "rgb(255, 243, 193)", "textFormat": { "type": "NUMBER", "decimalPlaces": 4 } }, - { "x": 17, "y": 15, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { "x": 19, "y": 15, "fillColor": "rgb(255, 243, 193)" }, - { - "x": 1, - "y": 18, - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 }, - "fillColor": "rgb(238, 238, 238)" - }, - { - "x": 3, - "y": 18, - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 }, - "fillColor": "rgb(238, 238, 238)" - }, - { - "x": 4, - "y": 18, - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 }, - "fillColor": "rgb(238, 238, 238)" - }, - { "x": 5, "y": 18, "textFormat": { "type": "NUMBER", "decimalPlaces": 1 }, "fillColor": "rgb(238, 238, 238)" }, - { "x": 11, "y": 18, "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, "fillColor": "rgb(238, 238, 238)" }, - { - "x": 13, - "y": 18, - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 }, - "fillColor": "rgb(238, 238, 238)" - }, - { - "x": 14, - "y": 18, - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 }, - "fillColor": "rgb(238, 238, 238)" - }, - { "x": 15, "y": 18, "textFormat": { "type": "NUMBER", "decimalPlaces": 4 }, "fillColor": "rgb(238, 238, 238)" }, - { "x": 1, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 5, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 11, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 13, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 15, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 1, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 2, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 3, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 4, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 5, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 1, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 2, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 3, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 4, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 5, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 6, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 7, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 8, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 9, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 10, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 11, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 12, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 13, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 14, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 15, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 16, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 17, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 18, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 19, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 8, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 9, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 10, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 11, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 14, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 15, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 20, "y": 0, "fillColor": "rgb(175, 208, 231)" }, - { "x": 17, "y": 6, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { "x": 17, "y": 10, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { "x": 17, "y": 13, "bold": true, "fillColor": "rgb(218, 240, 255)", "italic": true }, - { "x": 18, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 19, "y": 2, "fillColor": "rgb(218, 240, 255)" }, - { "x": 19, "y": 6, "fillColor": "rgb(255, 243, 193)" }, - { "x": 19, "y": 7, "fillColor": "rgb(255, 243, 193)" }, - { "x": 19, "y": 10, "fillColor": "rgb(255, 243, 193)" }, - { "x": 19, "y": 13, "fillColor": "rgb(255, 243, 193)" }, - { "x": 18, "y": 5, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 6, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 7, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 8, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 9, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 10, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 11, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 12, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 13, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 14, "fillColor": "rgb(218, 240, 255)" }, - { "x": 18, "y": 15, "fillColor": "rgb(218, 240, 255)" }, - { "x": 0, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { - "x": 2, - "y": 18, - "textFormat": { "type": "CURRENCY", "display": "CURRENCY", "symbol": "USD", "decimalPlaces": 0 }, - "fillColor": "rgb(238, 238, 238)" - }, - { "x": 6, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 7, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 8, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 9, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 10, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 12, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 16, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 17, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 18, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 19, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 20, "y": 18, "fillColor": "rgb(238, 238, 238)" }, - { "x": 0, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 2, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 3, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 4, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 6, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 7, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 8, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 9, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 10, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 12, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 14, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 16, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 17, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 18, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 19, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" }, - { "x": 20, "y": 19, "italic": true, "fillColor": "rgb(238, 238, 238)" } - ], - "borders": [ - { "x": 0, "y": 0, "vertical": {}, "horizontal": {} }, - { "x": 1, "y": 0, "horizontal": {} }, - { "x": 2, "y": 0, "horizontal": {} }, - { "x": 3, "y": 0, "horizontal": {} }, - { "x": 4, "y": 0, "horizontal": {} }, - { "x": 5, "y": 0, "horizontal": {} }, - { "x": 6, "y": 0, "horizontal": {} }, - { "x": 7, "y": 0, "horizontal": {} }, - { "x": 8, "y": 0, "horizontal": {} }, - { "x": 9, "y": 0, "horizontal": {} }, - { "x": 10, "y": 0, "horizontal": {} }, - { "x": 11, "y": 0, "horizontal": {} }, - { "x": 12, "y": 0, "horizontal": {} }, - { "x": 13, "y": 0, "horizontal": {} }, - { "x": 14, "y": 0, "horizontal": {} }, - { "x": 15, "y": 0, "horizontal": {} }, - { "x": 16, "y": 0, "horizontal": {} }, - { "x": 17, "y": 0, "horizontal": {} }, - { "x": 18, "y": 0, "horizontal": {} }, - { "x": 20, "y": 0, "horizontal": {} }, - { "x": 0, "y": 1, "horizontal": {}, "vertical": {} }, - { "x": 20, "y": 1, "horizontal": {} }, - { "x": 0, "y": 2, "vertical": {}, "horizontal": {} }, - { "x": 0, "y": 4, "vertical": {} }, - { "x": 0, "y": 5, "vertical": {} }, - { "x": 0, "y": 6, "vertical": {} }, - { "x": 0, "y": 7, "vertical": {} }, - { "x": 0, "y": 8, "vertical": {} }, - { "x": 0, "y": 9, "vertical": {} }, - { "x": 0, "y": 10, "vertical": {} }, - { "x": 0, "y": 11, "vertical": {} }, - { "x": 0, "y": 12, "vertical": {} }, - { "x": 0, "y": 13, "vertical": {} }, - { "x": 0, "y": 14, "vertical": {} }, - { "x": 0, "y": 15, "vertical": {} }, - { "x": 0, "y": 16, "horizontal": {}, "vertical": {} }, - { "x": 0, "y": 17, "vertical": {} }, - { "x": 0, "y": 18, "vertical": {}, "horizontal": {} }, - { "x": 0, "y": 19, "vertical": {} }, - { "x": 1, "y": 1, "horizontal": {} }, - { "x": 2, "y": 1, "horizontal": {} }, - { "x": 3, "y": 1, "horizontal": {} }, - { "x": 4, "y": 1, "horizontal": {} }, - { "x": 5, "y": 1, "horizontal": {} }, - { "x": 6, "y": 1, "horizontal": {} }, - { "x": 7, "y": 1, "horizontal": {} }, - { "x": 8, "y": 1, "horizontal": {} }, - { "x": 9, "y": 1, "horizontal": {} }, - { "x": 10, "y": 1, "horizontal": {} }, - { "x": 11, "y": 1, "horizontal": {} }, - { "x": 12, "y": 1, "horizontal": {} }, - { "x": 13, "y": 1, "horizontal": {} }, - { "x": 14, "y": 1, "horizontal": {} }, - { "x": 15, "y": 1, "horizontal": {} }, - { "x": 16, "y": 1, "horizontal": {} }, - { "x": 17, "y": 1, "horizontal": {} }, - { "x": 18, "y": 1, "horizontal": {} }, - { "x": 1, "y": 2, "horizontal": {} }, - { "x": 2, "y": 2, "horizontal": {} }, - { "x": 3, "y": 2, "horizontal": {} }, - { "x": 4, "y": 2, "horizontal": {} }, - { "x": 6, "y": 2, "vertical": {} }, - { "x": 5, "y": 2, "horizontal": {} }, - { "x": 6, "y": 4, "vertical": {} }, - { "x": 6, "y": 5, "vertical": {} }, - { "x": 6, "y": 6, "vertical": {} }, - { "x": 6, "y": 7, "vertical": {} }, - { "x": 6, "y": 8, "vertical": {} }, - { "x": 6, "y": 9, "vertical": {} }, - { "x": 6, "y": 10, "vertical": {} }, - { "x": 6, "y": 11, "vertical": {} }, - { "x": 6, "y": 12, "vertical": {} }, - { "x": 6, "y": 13, "vertical": {} }, - { "x": 6, "y": 14, "vertical": {} }, - { "x": 1, "y": 16, "horizontal": {} }, - { "x": 2, "y": 16, "horizontal": {} }, - { "x": 3, "y": 16, "horizontal": {} }, - { "x": 4, "y": 16, "horizontal": {} }, - { "x": 6, "y": 15, "vertical": {} }, - { "x": 5, "y": 16, "horizontal": {} }, - { "x": 7, "y": 2, "vertical": {}, "horizontal": {} }, - { "x": 8, "y": 2, "horizontal": {} }, - { "x": 9, "y": 2, "horizontal": {} }, - { "x": 10, "y": 2, "horizontal": {} }, - { "x": 12, "y": 2, "vertical": {} }, - { "x": 11, "y": 2, "horizontal": {} }, - { "x": 7, "y": 3, "horizontal": {}, "vertical": {} }, - { "x": 12, "y": 3, "vertical": {} }, - { "x": 7, "y": 4, "vertical": {} }, - { "x": 12, "y": 4, "vertical": {} }, - { "x": 7, "y": 5, "vertical": {} }, - { "x": 12, "y": 5, "vertical": {} }, - { "x": 7, "y": 6, "vertical": {} }, - { "x": 12, "y": 6, "vertical": {} }, - { "x": 7, "y": 7, "vertical": {} }, - { "x": 12, "y": 7, "vertical": {} }, - { "x": 7, "y": 8, "vertical": {} }, - { "x": 12, "y": 8, "vertical": {} }, - { "x": 7, "y": 9, "vertical": {} }, - { "x": 12, "y": 9, "vertical": {} }, - { "x": 7, "y": 10, "vertical": {} }, - { "x": 12, "y": 10, "vertical": {} }, - { "x": 7, "y": 11, "vertical": {} }, - { "x": 12, "y": 11, "vertical": {} }, - { "x": 7, "y": 12, "vertical": {} }, - { "x": 12, "y": 12, "vertical": {} }, - { "x": 7, "y": 13, "vertical": {} }, - { "x": 12, "y": 13, "vertical": {} }, - { "x": 7, "y": 14, "vertical": {} }, - { "x": 12, "y": 14, "vertical": {} }, - { "x": 7, "y": 15, "vertical": {} }, - { "x": 7, "y": 16, "horizontal": {} }, - { "x": 8, "y": 16, "horizontal": {} }, - { "x": 9, "y": 16, "horizontal": {} }, - { "x": 10, "y": 16, "horizontal": {} }, - { "x": 12, "y": 15, "vertical": {} }, - { "x": 11, "y": 16, "horizontal": {} }, - { "x": 8, "y": 3, "horizontal": {} }, - { "x": 9, "y": 3, "horizontal": {} }, - { "x": 10, "y": 3, "horizontal": {} }, - { "x": 11, "y": 3, "horizontal": {} }, - { "x": 0, "y": 3, "horizontal": {}, "vertical": {} }, - { "x": 6, "y": 3, "vertical": {} }, - { "x": 1, "y": 3, "horizontal": {} }, - { "x": 2, "y": 3, "horizontal": {} }, - { "x": 3, "y": 3, "horizontal": {} }, - { "x": 4, "y": 3, "horizontal": {} }, - { "x": 5, "y": 3, "horizontal": {} }, - { "x": 13, "y": 2, "vertical": {}, "horizontal": {} }, - { "x": 14, "y": 2, "horizontal": {} }, - { "x": 16, "y": 2, "vertical": {} }, - { "x": 15, "y": 2, "horizontal": {} }, - { "x": 13, "y": 3, "horizontal": {}, "vertical": {} }, - { "x": 16, "y": 3, "vertical": {} }, - { "x": 13, "y": 4, "vertical": {} }, - { "x": 16, "y": 4, "vertical": {} }, - { "x": 13, "y": 5, "vertical": {} }, - { "x": 16, "y": 5, "vertical": {} }, - { "x": 13, "y": 6, "vertical": {} }, - { "x": 16, "y": 6, "vertical": {} }, - { "x": 13, "y": 7, "vertical": {} }, - { "x": 16, "y": 7, "vertical": {} }, - { "x": 13, "y": 8, "vertical": {} }, - { "x": 16, "y": 8, "vertical": {} }, - { "x": 13, "y": 9, "vertical": {} }, - { "x": 16, "y": 9, "vertical": {} }, - { "x": 13, "y": 10, "vertical": {} }, - { "x": 16, "y": 10, "vertical": {} }, - { "x": 13, "y": 11, "vertical": {} }, - { "x": 16, "y": 11, "vertical": {} }, - { "x": 13, "y": 12, "vertical": {} }, - { "x": 16, "y": 12, "vertical": {} }, - { "x": 13, "y": 13, "vertical": {} }, - { "x": 16, "y": 13, "vertical": {} }, - { "x": 13, "y": 14, "vertical": {} }, - { "x": 16, "y": 14, "vertical": {} }, - { "x": 13, "y": 15, "vertical": {} }, - { "x": 13, "y": 16, "horizontal": {} }, - { "x": 14, "y": 16, "horizontal": {} }, - { "x": 16, "y": 15, "vertical": {} }, - { "x": 15, "y": 16, "horizontal": {} }, - { "x": 14, "y": 3, "horizontal": {} }, - { "x": 15, "y": 3, "horizontal": {} }, - { "x": 21, "y": 0, "vertical": {} }, - { "x": 21, "y": 1, "vertical": {} }, - { "x": 21, "y": 2, "vertical": {} }, - { "x": 21, "y": 3, "vertical": {} }, - { "x": 21, "y": 4, "vertical": {} }, - { "x": 21, "y": 5, "vertical": {} }, - { "x": 21, "y": 6, "vertical": {} }, - { "x": 21, "y": 7, "vertical": {} }, - { "x": 21, "y": 8, "vertical": {} }, - { "x": 21, "y": 9, "vertical": {} }, - { "x": 21, "y": 10, "vertical": {} }, - { "x": 21, "y": 11, "vertical": {} }, - { "x": 21, "y": 12, "vertical": {} }, - { "x": 21, "y": 13, "vertical": {} }, - { "x": 21, "y": 14, "vertical": {} }, - { "x": 21, "y": 15, "vertical": {} }, - { "x": 21, "y": 16, "vertical": {} }, - { "x": 21, "y": 17, "vertical": {} }, - { "x": 21, "y": 18, "vertical": {} }, - { "x": 21, "y": 19, "vertical": {} }, - { "x": 19, "y": 0, "horizontal": {} }, - { "x": 19, "y": 1, "horizontal": {} }, - { "x": 17, "y": 2, "vertical": {}, "horizontal": {} }, - { "x": 18, "y": 2, "horizontal": {} }, - { "x": 20, "y": 2, "vertical": {} }, - { "x": 19, "y": 2, "horizontal": {} }, - { "x": 17, "y": 3, "horizontal": {}, "vertical": {} }, - { "x": 20, "y": 3, "vertical": {} }, - { "x": 17, "y": 4, "vertical": {} }, - { "x": 20, "y": 4, "vertical": {} }, - { "x": 17, "y": 5, "vertical": {} }, - { "x": 20, "y": 5, "vertical": {} }, - { "x": 17, "y": 6, "vertical": {} }, - { "x": 20, "y": 6, "vertical": {} }, - { "x": 17, "y": 7, "vertical": {} }, - { "x": 20, "y": 7, "vertical": {} }, - { "x": 17, "y": 8, "vertical": {} }, - { "x": 20, "y": 8, "vertical": {} }, - { "x": 17, "y": 9, "vertical": {} }, - { "x": 20, "y": 9, "vertical": {} }, - { "x": 17, "y": 10, "vertical": {} }, - { "x": 20, "y": 10, "vertical": {} }, - { "x": 17, "y": 11, "vertical": {} }, - { "x": 20, "y": 11, "vertical": {} }, - { "x": 17, "y": 12, "vertical": {} }, - { "x": 20, "y": 12, "vertical": {} }, - { "x": 17, "y": 13, "vertical": {} }, - { "x": 20, "y": 13, "vertical": {} }, - { "x": 17, "y": 14, "vertical": {} }, - { "x": 20, "y": 14, "vertical": {} }, - { "x": 17, "y": 15, "vertical": {} }, - { "x": 17, "y": 16, "horizontal": {} }, - { "x": 18, "y": 16, "horizontal": {} }, - { "x": 20, "y": 15, "vertical": {} }, - { "x": 19, "y": 16, "horizontal": {} }, - { "x": 18, "y": 3, "horizontal": {} }, - { "x": 19, "y": 3, "horizontal": {} }, - { "x": 1, "y": 18, "horizontal": {} }, - { "x": 2, "y": 18, "horizontal": {} }, - { "x": 3, "y": 18, "horizontal": {} }, - { "x": 4, "y": 18, "horizontal": {} }, - { "x": 5, "y": 18, "horizontal": {} }, - { "x": 6, "y": 18, "horizontal": {} }, - { "x": 7, "y": 18, "horizontal": {} }, - { "x": 8, "y": 18, "horizontal": {} }, - { "x": 9, "y": 18, "horizontal": {} }, - { "x": 10, "y": 18, "horizontal": {} }, - { "x": 11, "y": 18, "horizontal": {} }, - { "x": 12, "y": 18, "horizontal": {} }, - { "x": 13, "y": 18, "horizontal": {} }, - { "x": 14, "y": 18, "horizontal": {} }, - { "x": 15, "y": 18, "horizontal": {} }, - { "x": 16, "y": 18, "horizontal": {} }, - { "x": 17, "y": 18, "horizontal": {} }, - { "x": 18, "y": 18, "horizontal": {} }, - { "x": 19, "y": 18, "horizontal": {} }, - { "x": 20, "y": 18, "horizontal": {} }, - { "x": 13, "y": 20, "horizontal": {} }, - { "x": 14, "y": 20, "horizontal": {} }, - { "x": 15, "y": 20, "horizontal": {} }, - { "x": 16, "y": 20, "horizontal": {} }, - { "x": 17, "y": 20, "horizontal": {} }, - { "x": 18, "y": 20, "horizontal": {} }, - { "x": 19, "y": 20, "horizontal": {} }, - { "x": 20, "y": 20, "horizontal": {} }, - { "x": 12, "y": 20, "horizontal": {} }, - { "x": 11, "y": 20, "horizontal": {} }, - { "x": 10, "y": 20, "horizontal": {} }, - { "x": 9, "y": 20, "horizontal": {} }, - { "x": 8, "y": 20, "horizontal": {} }, - { "x": 7, "y": 20, "horizontal": {} }, - { "x": 6, "y": 20, "horizontal": {} }, - { "x": 5, "y": 20, "horizontal": {} }, - { "x": 4, "y": 20, "horizontal": {} }, - { "x": 3, "y": 20, "horizontal": {} }, - { "x": 2, "y": 20, "horizontal": {} }, - { "x": 1, "y": 20, "horizontal": {} }, - { "x": 0, "y": 20, "horizontal": {} } - ] - } - ], - "cell_dependency": "{\"5,6\":[[4,6],[4,6],[4,6],[4,7],[4,7],[4,7],[4,8],[4,8],[4,8],[4,9],[4,9],[4,9],[4,10],[4,10],[4,10],[4,11],[4,11],[4,11],[4,12],[4,12],[4,12],[4,13],[4,13],[4,13],[4,14],[4,14],[4,14],[4,15],[4,15],[4,15],[3,15],[3,15],[3,15],[3,13],[3,13],[3,13],[3,10],[3,10],[3,10],[3,7],[3,7],[3,7],[3,14],[3,14],[3,14],[3,8],[3,8],[3,8],[3,9],[3,9],[3,9],[3,11],[3,11],[3,11],[3,6],[3,6],[3,6],[3,12],[3,12],[3,12]],\"19,8\":[[4,6],[4,7],[4,8],[4,9],[4,10],[4,11],[4,12],[4,13],[4,14],[4,15]],\"4,18\":[[4,6],[4,7],[4,8],[4,9],[4,10],[4,11],[4,12],[4,13],[4,14],[4,15]],\"13,6\":[[4,6],[4,7],[4,8],[4,9],[4,10],[4,11],[4,12],[4,13],[4,14],[4,15],[5,6],[5,7],[5,8],[5,9],[5,10],[5,11],[5,12],[5,13],[5,14],[5,15],[11,9],[11,7],[11,10],[11,8],[11,6],[11,11],[11,12],[11,15],[11,14],[11,13]],\"15,6\":[[4,6],[4,7],[4,8],[4,9],[4,10],[4,11],[4,12],[4,13],[4,14],[4,15],[13,12],[13,13],[13,7],[13,14],[13,15],[13,8],[13,9],[13,10],[13,6],[13,11]],\"19,9\":[[5,6],[5,7],[5,8],[5,9],[5,10],[5,11],[5,12],[5,13],[5,14],[5,15]],\"5,18\":[[5,6],[5,7],[5,8],[5,9],[5,10],[5,11],[5,12],[5,13],[5,14],[5,15]],\"19,11\":[[14,6],[14,7],[14,8],[14,9],[14,10],[14,11],[14,12],[14,13],[14,14],[14,15]],\"14,18\":[[14,6],[14,7],[14,8],[14,9],[14,10],[14,11],[14,12],[14,13],[14,14],[14,15]],\"19,12\":[[15,6],[15,7],[15,8],[15,9],[15,10],[15,11],[15,12],[15,13],[15,14],[15,15]],\"15,18\":[[15,6],[15,7],[15,8],[15,9],[15,10],[15,11],[15,12],[15,13],[15,14],[15,15]],\"14,6\":[[15,6],[15,7],[15,7],[15,7],[15,7],[15,7],[15,7],[15,8],[15,8],[15,8],[15,8],[15,8],[15,8],[15,9],[15,9],[15,9],[15,9],[15,9],[15,9],[15,10],[15,10],[15,10],[15,10],[15,10],[15,10],[15,11],[15,11],[15,11],[15,11],[15,11],[15,11],[15,12],[15,12],[15,12],[15,12],[15,12],[15,12],[15,13],[15,13],[15,13],[15,13],[15,13],[15,13],[15,14],[15,14],[15,14],[15,14],[15,14],[15,14],[15,15],[15,15],[15,15],[15,15],[15,15],[15,15],[1,7],[1,7],[1,7],[1,7],[1,7],[1,7],[1,12],[1,12],[1,12],[1,12],[1,12],[1,12],[1,15],[1,15],[1,15],[1,15],[1,15],[1,15],[1,9],[1,9],[1,9],[1,9],[1,9],[1,9],[1,8],[1,8],[1,8],[1,8],[1,8],[1,8],[1,10],[1,10],[1,10],[1,10],[1,10],[1,10],[1,13],[1,13],[1,13],[1,13],[1,13],[1,13],[1,14],[1,14],[1,14],[1,14],[1,14],[1,14],[1,6],[1,11],[1,11],[1,11],[1,11],[1,11],[1,11]],\"1,18\":[[1,7],[1,12],[1,15],[1,9],[1,8],[1,10],[1,13],[1,14],[1,6],[1,11]],\"3,18\":[[3,15],[3,13],[3,10],[3,7],[3,14],[3,8],[3,9],[3,11],[3,6],[3,12]],\"8,6\":[[7,6],[7,6],[7,6],[7,6]],\"8,7\":[[7,7],[7,7],[7,7]],\"8,8\":[[7,8],[7,8]],\"8,9\":[[7,9],[7,9]],\"8,13\":[[7,13],[7,13]],\"8,14\":[[7,14],[7,14]],\"14,22\":[[13,12],[13,13],[13,7],[13,14],[13,15],[13,8],[13,9],[13,10],[13,6],[13,11]],\"13,18\":[[13,12],[13,13],[13,7],[13,14],[13,15],[13,8],[13,9],[13,10],[13,6],[13,11]],\"11,18\":[[11,9],[11,7],[11,10],[11,8],[11,6],[11,11],[11,12],[11,15],[11,14],[11,13]],\"19,5\":[[1,18]],\"8,15\":[[7,15]],\"8,10\":[[7,10]],\"8,11\":[[7,11]],\"8,12\":[[7,12]],\"19,14\":[[15,18]]}", - "version": "1.4" -} diff --git a/quadratic-core/src/bin/export_types.rs b/quadratic-core/src/bin/export_types.rs index 49970a727f..d83a0a5e9d 100644 --- a/quadratic-core/src/bin/export_types.rs +++ b/quadratic-core/src/bin/export_types.rs @@ -29,18 +29,12 @@ fn main() { formulas::CellRef, formulas::CellRefCoord, grid::GridBounds, - // grid::CodeCellValue, - // grid::CodeCellRunOutput, - // grid::CodeCellRunResult, grid::CellAlign, grid::CellWrap, grid::NumericFormat, grid::NumericFormatKind, grid::BoolSummary, grid::SheetId, - grid::RowId, - grid::ColumnId, - grid::CellRef, grid::js_types::JsRenderCell, grid::js_types::JsRenderFill, grid::js_types::FormattingSummary, diff --git a/quadratic-core/src/computation/eval_formula.rs b/quadratic-core/src/computation/eval_formula.rs deleted file mode 100644 index 933e4dedaa..0000000000 --- a/quadratic-core/src/computation/eval_formula.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::{ - controller::{update_code_cell_value::update_code_cell_value, GridController}, - formulas::{parse_formula, Ctx}, - grid::{ - CellRef, CodeCellLanguage, CodeCellRunOutput, CodeCellRunResult, CodeCellValue, SheetId, - }, - Pos, SheetPos, -}; - -use super::TransactionInProgress; - -impl TransactionInProgress { - pub(super) fn eval_formula( - &mut self, - grid_controller: &mut GridController, - code_string: String, - language: CodeCellLanguage, - pos: Pos, - cell_ref: CellRef, - sheet_id: SheetId, - ) { - let mut ctx = Ctx::new( - grid_controller.grid(), - SheetPos { - sheet_id, - x: pos.x, - y: pos.y, - }, - ); - match parse_formula(&code_string, pos) { - Ok(parsed) => { - match parsed.eval(&mut ctx) { - Ok(value) => { - self.cells_accessed = ctx - .cells_accessed - .iter() - .map(|sheet_pos| { - let sheet = grid_controller - .grid_mut() - .sheet_mut_from_id(sheet_pos.sheet_id); - let pos = (*sheet_pos).into(); - sheet.get_or_create_cell_ref(pos) - }) - .collect(); - - let updated_code_cell_value = CodeCellValue { - language, - code_string, - formatted_code_string: None, - output: Some(CodeCellRunOutput { - std_out: None, - std_err: None, - result: CodeCellRunResult::Ok { - output_value: value, - cells_accessed: self.cells_accessed.clone(), - }, - spill: false, - }), - // todo - last_modified: String::new(), - }; - if update_code_cell_value( - grid_controller, - cell_ref, - Some(updated_code_cell_value), - &mut self.cells_to_compute, - &mut self.reverse_operations, - &mut self.summary, - ) { - // clears cells_accessed - self.cells_accessed.clear(); - } - } - Err(error) => { - let msg = error.msg.to_string(); - let line_number = error.span.map(|span| span.start as i64); - self.code_cell_sheet_error( - grid_controller, - msg, - // todo: span should be multiline - line_number, - ); - } - } - } - Err(e) => { - let msg = e.to_string(); - self.code_cell_sheet_error(grid_controller, msg, None); - } - } - } -} diff --git a/quadratic-core/src/computation/mod.rs b/quadratic-core/src/computation/mod.rs deleted file mode 100644 index 54af284558..0000000000 --- a/quadratic-core/src/computation/mod.rs +++ /dev/null @@ -1,36 +0,0 @@ -pub mod eval_formula; -pub mod get_cells; -pub mod transaction_in_progress; -use std::collections::HashSet; - -use indexmap::IndexSet; - -use crate::grid::{CellRef, CodeCellLanguage, CodeCellValue, RegionRef, SheetId}; - -use crate::controller::{ - operation::Operation, transaction_summary::TransactionSummary, transactions::TransactionType, -}; - -// only one InProgressTransaction can exist at a time (or no Transaction) - -#[derive(Debug, Default, Clone)] -pub struct TransactionInProgress { - reverse_operations: Vec, - cells_updated: IndexSet, - cells_to_compute: IndexSet, - pub cursor: Option, - cells_accessed: Vec, - pub summary: TransactionSummary, - sheets_with_changed_bounds: HashSet, - pub transaction_type: TransactionType, - - // tracks whether there are any async calls (which changes how the transaction is finalized) - pub has_async: bool, - - // save code_cell info for async calls - current_code_cell: Option, - pub current_cell_ref: Option, - waiting_for_async: Option, - // true when transaction completes - pub complete: bool, -} diff --git a/quadratic-core/src/controller.rs b/quadratic-core/src/controller.rs index 6577db51e0..1f12d339c1 100644 --- a/quadratic-core/src/controller.rs +++ b/quadratic-core/src/controller.rs @@ -1,20 +1,23 @@ +use std::collections::HashSet; + +use indexmap::IndexSet; #[cfg(feature = "js")] use wasm_bindgen::prelude::*; -use crate::{computation::TransactionInProgress, grid::Grid}; +use crate::{ + grid::{CodeCellLanguage, Grid, SheetId}, + SheetPos, SheetRect, +}; -use self::transactions::Transaction; +use self::{ + execution::TransactionType, operations::operation::Operation, + transaction_summary::TransactionSummary, +}; -pub mod auto_complete; -pub mod borders; -pub mod cells; -pub mod clipboard; pub mod dependencies; +pub mod execution; pub mod export; -pub mod formatting; pub mod formula; -pub mod import; -pub mod operation; pub mod operations; pub mod sheet_offsets; pub mod sheets; @@ -22,16 +25,51 @@ pub mod spills; pub mod thumbnail; pub mod transaction_summary; pub mod transaction_types; -pub mod transactions; pub mod update_code_cell_value; +pub mod user_actions; + +#[derive(Debug, Default, Clone, PartialEq)] +pub struct Transaction { + operations: Vec, + cursor: Option, +} -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, PartialEq)] #[cfg_attr(feature = "js", wasm_bindgen)] pub struct GridController { grid: Grid, - transaction_in_progress: Option, undo_stack: Vec, redo_stack: Vec, + + // transaction in progress information + transaction_in_progress: bool, + cursor: Option, + transaction_type: TransactionType, + + // queue of cells to compute + cells_to_compute: IndexSet, + + // track changes + cells_updated: IndexSet, + cells_accessed: HashSet, + summary: TransactionSummary, + sheets_with_changed_bounds: HashSet, + + // tracks whether there are any async calls (which changes how the transaction is finalized) + has_async: bool, + + // save code_cell info for async calls + current_sheet_pos: Option, + waiting_for_async: Option, + + // true when transaction completes + complete: bool, + + // undo operations + reverse_operations: Vec, + + // operations for multiplayer + forward_operations: Vec, } impl GridController { @@ -41,9 +79,7 @@ impl GridController { pub fn from_grid(grid: Grid) -> Self { GridController { grid, - transaction_in_progress: None, - undo_stack: vec![], - redo_stack: vec![], + ..Default::default() } } pub fn grid(&self) -> &Grid { @@ -53,10 +89,3 @@ impl GridController { &mut self.grid } } - -#[cfg(test)] -impl GridController { - pub fn get_transaction_in_progress(&self) -> Option<&TransactionInProgress> { - self.transaction_in_progress.as_ref() - } -} diff --git a/quadratic-core/src/controller/cells.rs b/quadratic-core/src/controller/cells.rs deleted file mode 100644 index c8ec4be049..0000000000 --- a/quadratic-core/src/controller/cells.rs +++ /dev/null @@ -1,390 +0,0 @@ -use std::str::FromStr; - -use bigdecimal::BigDecimal; - -use crate::{ - grid::{ - generate_borders, BorderSelection, CodeCellLanguage, CodeCellValue, NumericDecimals, - NumericFormat, NumericFormatKind, RegionRef, SheetId, - }, - util::date_string, - Array, CellValue, Pos, Rect, RunLengthEncoding, -}; - -use super::{ - formatting::CellFmtArray, operation::Operation, transaction_summary::TransactionSummary, - transactions::TransactionType, GridController, -}; - -impl GridController { - pub fn populate_with_random_floats(&mut self, sheet_id: SheetId, region: &Rect) { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - sheet.with_random_floats(region); - } - - /// sets the value based on a user's input and converts input to proper NumericFormat - pub fn set_cell_value( - &mut self, - sheet_id: SheetId, - pos: Pos, - value: String, - cursor: Option, - ) -> TransactionSummary { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - let cell_ref = sheet.get_or_create_cell_ref(pos); - let mut ops = vec![]; - - let cell_value = self.string_to_cell_value(sheet_id, pos, value.as_str(), &mut ops); - - ops.push(Operation::SetCellValues { - region: RegionRef::from(cell_ref), - values: Array::from(cell_value), - }); - - self.set_in_progress_transaction(ops, cursor, true, TransactionType::Normal) - } - - pub fn string_to_cell_value( - &mut self, - sheet_id: SheetId, - pos: Pos, - value: &str, - formatting_ops: &mut Vec, - ) -> CellValue { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - let cell_ref = sheet.get_or_create_cell_ref(pos); - let region = RegionRef::from(cell_ref); - - // strip whitespace - let value = value.trim(); - - if value.is_empty() { - CellValue::Blank - } else if let Some((currency, number)) = CellValue::unpack_currency(value) { - let numeric_format = NumericFormat { - kind: NumericFormatKind::Currency, - symbol: Some(currency), - }; - formatting_ops.push(Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( - Some(numeric_format), - 1, - )), - }); - // only change decimal places if decimals have not been set - if sheet.get_formatting_value::(pos).is_none() { - formatting_ops.push(Operation::SetCellFormats { - region, - attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat(Some(2), 1)), - }); - } - CellValue::Number(number) - } else if let Ok(bd) = BigDecimal::from_str(value) { - CellValue::Number(bd) - } else if let Some(percent) = CellValue::unpack_percentage(value) { - let numeric_format = NumericFormat { - kind: NumericFormatKind::Percentage, - symbol: None, - }; - formatting_ops.push(Operation::SetCellFormats { - region, - attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( - Some(numeric_format), - 1, - )), - }); - - CellValue::Number(percent) - } else { - CellValue::Text(value.into()) - } - } - - pub fn set_cell_code( - &mut self, - sheet_id: SheetId, - pos: Pos, - language: CodeCellLanguage, - code_string: String, - cursor: Option, - ) -> TransactionSummary { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - let cell_ref = sheet.get_or_create_cell_ref(pos); - let mut ops = vec![]; - - // remove any values that were originally over the code cell - if sheet.get_cell_value_only(pos).is_some() { - ops.push(Operation::SetCellValues { - region: RegionRef::from(cell_ref), - values: Array::from(CellValue::Blank), - }); - } - - ops.push(Operation::SetCellCode { - cell_ref, - code_cell_value: Some(CodeCellValue { - language, - code_string, - formatted_code_string: None, - output: None, - last_modified: date_string(), - }), - }); - self.set_in_progress_transaction(ops, cursor, true, TransactionType::Normal) - } - - /// Generates and returns the set of operations to deleted the values and code in a given region - /// Does not commit the operations or create a transaction. - pub fn delete_cells_rect_operations( - &mut self, - sheet_id: SheetId, - rect: Rect, - ) -> Vec { - let region = self.existing_region(sheet_id, rect); - let mut ops = vec![]; - if let Some(size) = region.size() { - let values = Array::new_empty(size); - ops.push(Operation::SetCellValues { - region: region.clone(), - values, - }); - - let sheet = self.grid.sheet_from_id(sheet_id); - - // collect all the code cells in the region - for cell_ref in sheet.code_cells.keys() { - if region.contains(cell_ref) { - ops.push(Operation::SetCellCode { - cell_ref: *cell_ref, - code_cell_value: None, - }); - } - } - }; - ops - } - - /// Deletes the cell values and code in a given region. - /// Creates and runs a transaction, also updates dependent cells. - /// Returns a [`TransactionSummary`]. - pub fn delete_cells_rect( - &mut self, - sheet_id: SheetId, - rect: Rect, - cursor: Option, - ) -> TransactionSummary { - let ops = self.delete_cells_rect_operations(sheet_id, rect); - self.set_in_progress_transaction(ops, cursor, true, TransactionType::Normal) - } - - pub fn clear_formatting_operations(&mut self, sheet_id: SheetId, rect: Rect) -> Vec { - let region = self.existing_region(sheet_id, rect); - match region.size() { - Some(_) => { - let len = region.size().unwrap().len(); - let mut ops = vec![ - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::Align(RunLengthEncoding::repeat(None, len)), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::Wrap(RunLengthEncoding::repeat(None, len)), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat(None, len)), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat(None, len)), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::Bold(RunLengthEncoding::repeat(None, len)), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::Italic(RunLengthEncoding::repeat(None, len)), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::TextColor(RunLengthEncoding::repeat(None, len)), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::FillColor(RunLengthEncoding::repeat(None, len)), - }, - ]; - - // clear borders - let sheet = self.grid.sheet_from_id(sheet_id); - let borders = generate_borders(sheet, ®ion, vec![BorderSelection::Clear], None); - ops.push(Operation::SetBorders { - region: region.clone(), - borders, - }); - ops - } - None => vec![], - } - } - - pub fn clear_formatting( - &mut self, - sheet_id: SheetId, - rect: Rect, - cursor: Option, - ) -> TransactionSummary { - let ops = self.clear_formatting_operations(sheet_id, rect); - self.set_in_progress_transaction(ops, cursor, false, TransactionType::Normal) - } - - pub fn delete_values_and_formatting( - &mut self, - sheet_id: SheetId, - rect: Rect, - cursor: Option, - ) -> TransactionSummary { - let mut ops = self.delete_cells_rect_operations(sheet_id, rect); - ops.extend(self.clear_formatting_operations(sheet_id, rect)); - self.set_in_progress_transaction(ops, cursor, true, TransactionType::Normal) - } - - /// Returns a region of the spreadsheet, assigning IDs to columns and rows - /// as needed. - pub fn region(&mut self, sheet_id: SheetId, rect: Rect) -> RegionRef { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - sheet.region(rect) - } - /// Returns a region of the spreadsheet, ignoring columns and rows which - /// have no contents and no IDs. - pub fn existing_region(&self, sheet_id: SheetId, rect: Rect) -> RegionRef { - let sheet = self.grid.sheet_from_id(sheet_id); - sheet.existing_region(rect) - } -} - -#[cfg(test)] -mod test { - use crate::{ - controller::{transaction_summary::CellSheetsModified, GridController}, - grid::{NumericDecimals, NumericFormat}, - CellValue, Pos, - }; - use std::{collections::HashSet, str::FromStr}; - - use bigdecimal::BigDecimal; - - #[test] - fn test_set_cell_value_undo_redo() { - let mut g = GridController::new(); - let sheet_id = g.grid.sheets()[0].id; - let pos = Pos { x: 3, y: 6 }; - let get_the_cell = - |g: &GridController| g.sheet(sheet_id).get_cell_value(pos).unwrap_or_default(); - let mut cell_sheets_modified = HashSet::new(); - cell_sheets_modified.insert(CellSheetsModified::new(sheet_id, pos)); - assert_eq!(get_the_cell(&g), CellValue::Blank); - g.set_cell_value(sheet_id, pos, String::from("a"), None); - assert_eq!(get_the_cell(&g), CellValue::Text(String::from("a"))); - g.set_cell_value(sheet_id, pos, String::from("b"), None); - assert_eq!(get_the_cell(&g), CellValue::Text(String::from("b"))); - assert_eq!(g.undo(None).cell_sheets_modified, cell_sheets_modified); - assert_eq!(get_the_cell(&g), CellValue::Text(String::from("a"))); - assert_eq!(g.redo(None).cell_sheets_modified, cell_sheets_modified); - assert_eq!(get_the_cell(&g), CellValue::Text(String::from("b"))); - assert_eq!(g.undo(None).cell_sheets_modified, cell_sheets_modified); - assert_eq!(get_the_cell(&g), CellValue::Text(String::from("a"))); - assert_eq!(g.undo(None).cell_sheets_modified, cell_sheets_modified); - assert_eq!(get_the_cell(&g), CellValue::Blank); - assert_eq!(g.undo(None).cell_sheets_modified, HashSet::default()); - assert_eq!(get_the_cell(&g), CellValue::Blank); - assert_eq!(g.redo(None).cell_sheets_modified, cell_sheets_modified); - assert_eq!(get_the_cell(&g), CellValue::Text(String::from("a"))); - assert_eq!(g.redo(None).cell_sheets_modified, cell_sheets_modified); - assert_eq!(get_the_cell(&g), CellValue::Text(String::from("b"))); - assert_eq!(g.redo(None).cell_sheets_modified, HashSet::default()); - assert_eq!(get_the_cell(&g), CellValue::Text(String::from("b"))); - } - - #[test] - fn test_unpack_currency() { - let value = String::from("$123.123"); - assert_eq!( - CellValue::unpack_currency(&value), - Some((String::from("$"), BigDecimal::from_str("123.123").unwrap())) - ); - - let value = String::from("test"); - assert_eq!(CellValue::unpack_currency(&value), None); - - let value = String::from("$123$123"); - assert_eq!(CellValue::unpack_currency(&value), None); - - let value = String::from("$123.123abc"); - assert_eq!(CellValue::unpack_currency(&value), None); - } - - #[test] - fn test_set_cell_value() { - let mut gc = GridController::new(); - let sheet_id = gc.grid.sheets()[0].id; - let pos = Pos { x: 0, y: 0 }; - let get_cell_value = - |g: &GridController| g.sheet(sheet_id).get_cell_value(pos).unwrap_or_default(); - let get_cell_numeric_format = - |g: &GridController| g.sheet(sheet_id).get_formatting_value::(pos); - let get_cell_numeric_decimals = |g: &GridController| { - g.sheet(sheet_id) - .get_formatting_value::(pos) - }; - - // empty string converts to blank cell value - gc.set_cell_value(sheet_id, pos, " ".into(), None); - assert_eq!(get_cell_value(&gc), CellValue::Blank); - - // currency - gc.set_cell_value(sheet_id, pos, "$1.22".into(), None); - assert_eq!( - get_cell_value(&gc), - CellValue::Number(BigDecimal::from_str("1.22").unwrap()) - ); - assert_eq!( - get_cell_numeric_format(&gc), - Some(NumericFormat { - kind: crate::grid::NumericFormatKind::Currency, - symbol: Some("$".into()) - }) - ); - assert_eq!(get_cell_numeric_decimals(&gc), Some(2)); - - // number - gc.set_cell_value(sheet_id, pos, "1.22".into(), None); - assert_eq!( - get_cell_value(&gc), - CellValue::Number(BigDecimal::from_str("1.22").unwrap()) - ); - assert_eq!(get_cell_numeric_decimals(&gc), Some(2)); - - // percentage - gc.set_cell_value(sheet_id, pos, "10.55%".into(), None); - assert_eq!( - get_cell_value(&gc), - CellValue::Number(BigDecimal::from_str(".1055").unwrap()) - ); - assert_eq!( - get_cell_numeric_format(&gc), - Some(NumericFormat { - kind: crate::grid::NumericFormatKind::Percentage, - symbol: None - }) - ); - assert_eq!(get_cell_numeric_decimals(&gc), Some(2)); - - // array - gc.set_cell_value(sheet_id, pos, "[1,2,3]".into(), None); - assert_eq!(get_cell_value(&gc), CellValue::Text("[1,2,3]".into())); - } -} diff --git a/quadratic-core/src/controller/dependencies.rs b/quadratic-core/src/controller/dependencies.rs index 28dd0f742f..5776097e57 100644 --- a/quadratic-core/src/controller/dependencies.rs +++ b/quadratic-core/src/controller/dependencies.rs @@ -2,21 +2,21 @@ use std::{self}; use std::collections::HashSet; -use crate::grid::{CellRef, RegionRef}; +use crate::{SheetPos, SheetRect}; use super::GridController; impl GridController { - pub fn get_dependent_cells(&self, cell: CellRef) -> Option> { + pub fn get_dependent_cells(&self, cell: SheetPos) -> Option> { let mut dependent_cells = HashSet::new(); self.grid.sheets().iter().for_each(|sheet| { - sheet.code_cells.iter().for_each(|(cell_ref, code_cell)| { + sheet.code_cells.iter().for_each(|(pos, code_cell)| { if let Some(output) = code_cell.output.as_ref() { if let Some(cells_accessed) = output.cells_accessed() { cells_accessed.iter().for_each(|cell_accessed| { if *cell_accessed == cell { - dependent_cells.insert(*cell_ref); + dependent_cells.insert(pos.to_sheet_pos(sheet.id)); } }); } @@ -31,16 +31,19 @@ impl GridController { Some(dependent_cells) } - pub fn get_dependent_cells_for_region(&self, region: RegionRef) -> Option> { + pub fn get_dependent_cells_for_sheet_rect( + &self, + sheet_rect: &SheetRect, + ) -> Option> { let mut dependent_cells = HashSet::new(); self.grid.sheets().iter().for_each(|sheet| { - sheet.code_cells.iter().for_each(|(cell_ref, code_cell)| { + sheet.code_cells.iter().for_each(|(pos, code_cell)| { if let Some(output) = code_cell.output.as_ref() { if let Some(cells_accessed) = output.cells_accessed() { cells_accessed.iter().for_each(|cell_accessed| { - if region.contains(cell_accessed) { - dependent_cells.insert(*cell_ref); + if sheet_rect.contains(*cell_accessed) { + dependent_cells.insert(pos.to_sheet_pos(sheet.id)); } }); } @@ -58,10 +61,12 @@ impl GridController { #[cfg(test)] mod test { + use std::collections::HashSet; + use crate::{ controller::GridController, grid::{CodeCellRunOutput, CodeCellValue}, - CellValue, Pos, Value, + CellValue, Pos, SheetPos, Value, }; #[test] @@ -70,13 +75,21 @@ mod test { let cdc = gc.grid_mut(); let sheet_id = cdc.sheet_ids()[0]; let sheet = cdc.sheet_mut_from_id(sheet_id); - sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Number(1.into())); - sheet.set_cell_value(Pos { x: 0, y: 1 }, CellValue::Number(2.into())); - let mut cells_accessed = vec![]; - let cell_ref00 = sheet.get_or_create_cell_ref(Pos { x: 0, y: 0 }); - let cell_ref01 = sheet.get_or_create_cell_ref(Pos { x: 0, y: 1 }); - cells_accessed.push(cell_ref00); - cells_accessed.push(cell_ref01); + let _ = sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Number(1.into())); + let _ = sheet.set_cell_value(Pos { x: 0, y: 1 }, CellValue::Number(2.into())); + let mut cells_accessed = HashSet::new(); + let sheet_pos_00 = SheetPos { + x: 0, + y: 0, + sheet_id, + }; + let sheet_pos_01 = SheetPos { + x: 0, + y: 1, + sheet_id, + }; + cells_accessed.insert(sheet_pos_00); + cells_accessed.insert(sheet_pos_01); sheet.set_code_cell_value( Pos { x: 0, y: 2 }, Some(CodeCellValue { @@ -95,17 +108,21 @@ mod test { }), }), ); - let cell_ref02 = sheet.get_or_create_cell_ref(Pos { x: 0, y: 2 }); + let sheet_pos_02 = SheetPos { + x: 0, + y: 2, + sheet_id, + }; - assert_eq!(gc.get_dependent_cells(cell_ref00).unwrap().len(), 1); + assert_eq!(gc.get_dependent_cells(sheet_pos_00).unwrap().len(), 1); assert_eq!( - gc.get_dependent_cells(cell_ref00).unwrap().iter().next(), - Some(&cell_ref02) + gc.get_dependent_cells(sheet_pos_00).unwrap().iter().next(), + Some(&sheet_pos_02) ); assert_eq!( - gc.get_dependent_cells(cell_ref01).unwrap().iter().next(), - Some(&cell_ref02) + gc.get_dependent_cells(sheet_pos_01).unwrap().iter().next(), + Some(&sheet_pos_02) ); - assert_eq!(gc.get_dependent_cells(cell_ref02), None); + assert_eq!(gc.get_dependent_cells(sheet_pos_02), None); } } diff --git a/quadratic-core/src/computation/transaction_in_progress.rs b/quadratic-core/src/controller/execution/compute.rs similarity index 51% rename from quadratic-core/src/computation/transaction_in_progress.rs rename to quadratic-core/src/controller/execution/compute.rs index 4a818b9ce5..69a6040340 100644 --- a/quadratic-core/src/computation/transaction_in_progress.rs +++ b/quadratic-core/src/controller/execution/compute.rs @@ -1,205 +1,105 @@ -use std::collections::HashSet; - -use indexmap::IndexSet; use wasm_bindgen::JsValue; use crate::{ - controller::update_code_cell_value::update_code_cell_value, - grid::{CodeCellLanguage, CodeCellRunOutput, CodeCellRunResult}, + controller::{transaction_types::JsCodeResult, GridController}, + grid::{CodeCellLanguage, CodeCellRunOutput, CodeCellRunResult, CodeCellValue}, util::date_string, - Error, ErrorMsg, Span, -}; - -use crate::controller::{ - operation::Operation, - transaction_summary::TransactionSummary, - transaction_types::JsCodeResult, - transactions::{Transaction, TransactionType}, - GridController, + Array, CellValue, Error, ErrorMsg, SheetPos, Span, Value, }; -use super::TransactionInProgress; - -impl TransactionInProgress { - /// Creates and runs a new Transaction - /// - /// Description - /// * `compute` triggers the computation cycle - pub fn start_transaction( - grid_controller: &mut GridController, - operations: Vec, - cursor: Option, - compute: bool, - transaction_type: TransactionType, - ) -> Self { - let mut transaction = Self { - reverse_operations: vec![], - summary: TransactionSummary::default(), - cursor, - transaction_type, - cells_updated: IndexSet::new(), - cells_to_compute: IndexSet::new(), - cells_accessed: vec![], - sheets_with_changed_bounds: HashSet::new(), - - has_async: false, - - current_code_cell: None, - current_cell_ref: None, - waiting_for_async: None, - - complete: false, - }; - - // apply operations - transaction.transact(grid_controller, operations, compute); - - // crate::util::dbgjs(&format!( - // "[CellsToCompute len] {}", - // transaction.cells_to_compute.len() - // )); - - // run computations - if compute { - transaction.loop_compute(grid_controller); - } else { - transaction.complete = true; +impl GridController { + /// checks the next cell in the cells_to_compute and computes it + /// returns true if an async call is made or the compute cycle is completed + pub(super) fn compute(&mut self) { + while let Some(sheet_rect) = self.cells_updated.shift_remove_index(0) { + #[cfg(feature = "show-operations")] + crate::util::dbgjs(format!("[Computing Cells] Checking: {:?}", sheet_rect)); + if let Some(dependent_cells) = self.get_dependent_cells_for_sheet_rect(&sheet_rect) { + self.cells_to_compute.extend(dependent_cells); + } } - transaction - } + if let Some(sheet_pos) = self.cells_to_compute.shift_remove_index(0) { + // todo: this would be a good place to check for cycles + // add all dependent cells to the cells_to_compute + if let Some(dependent_cells) = self.get_dependent_cells(sheet_pos) { + #[cfg(feature = "show-operations")] + dependent_cells.iter().for_each(|sheet_pos| { + crate::util::dbgjs(format!("[Adding Dependent Cell] {:?}", sheet_pos)); + }); - // loop compute cycle until complete or an async call is made - pub fn loop_compute(&mut self, grid_controller: &mut GridController) { - loop { - self.compute(grid_controller); - if self.waiting_for_async.is_some() { - break; - } - if self.cells_to_compute.is_empty() { - self.complete = true; - self.summary.save = true; - if self.has_async { - grid_controller.finalize_transaction(self); - } - break; + self.cells_to_compute.extend(dependent_cells); } - } - } - /// Clear the `cells_to_compute` attribute - pub fn clear_cells_to_compute(&mut self) { - self.cells_to_compute.clear(); - } - - /// recalculate bounds for changed sheets - pub fn updated_bounds(&mut self, grid_controller: &mut GridController) { - self.sheets_with_changed_bounds.iter().for_each(|sheet_id| { - let sheet = grid_controller.grid_mut().sheet_mut_from_id(*sheet_id); - sheet.recalculate_bounds(); - }); - } + // whether to save the current code_cell_ref to the GridController + let mut current_code_cell = false; - /// returns the TransactionSummary - pub fn transaction_summary(&mut self) -> TransactionSummary { - let summary = self.summary.clone(); - self.summary.clear(); - summary - } + let sheet = self.grid().sheet_from_id(sheet_pos.sheet_id); + // find which cells have code. Run the code and update the cells. + // add the updated cells to the cells_to_compute - /// executes a set of operations - fn transact( - &mut self, - grid_controller: &mut GridController, - operations: Vec, - compute: bool, - ) { - for op in operations.iter() { - if cfg!(feature = "show-operations") { - crate::util::dbgjs(&format!("[Operation] {:?}", op.to_string())); + if let Some(code_cell) = sheet.get_code_cell(sheet_pos.into()) { + current_code_cell = true; + let code_string = code_cell.code_string.clone(); + let language = code_cell.language; + match language { + CodeCellLanguage::Python => { + // python is run async so we exit the compute cycle and wait for TS to restart the transaction + if !cfg!(test) { + let result = crate::wasm_bindings::js::runPython(code_string); + + // run python will return false if python is not loaded (this can be generalized if we need to return a different error) + if result == JsValue::FALSE { + self.code_cell_sheet_error( + "Python interpreter not yet loaded (please run again)" + .to_string(), + None, + ); + return; + } + } + self.waiting_for_async = Some(language); + self.has_async = true; + } + CodeCellLanguage::Formula => { + self.eval_formula(code_string.clone(), language, sheet_pos); + } + _ => { + crate::util::dbgjs(format!( + "Compute language {} not supported in compute.rs", + language + )); + } + } + } + if current_code_cell { + self.current_sheet_pos = Some(sheet_pos); } - - let reverse_operation = grid_controller.execute_operation( - op.clone(), - &mut self.cells_updated, - &mut self.cells_to_compute, - &mut self.summary, - &mut self.sheets_with_changed_bounds, - compute, - ); - self.reverse_operations.extend(reverse_operation); } } - pub(super) fn code_cell_sheet_error( - &mut self, - grid_controller: &mut GridController, - error_msg: String, - line_number: Option, - ) { - let cell_ref = if let Some(cell_ref) = self.current_cell_ref { - cell_ref - } else { - // this should only happen after an internal logic error - crate::util::dbgjs( - "Expected current_sheet_pos to be defined in transaction::code_cell_error", - ); - return; - }; - let mut updated_code_cell_value = - if let Some(code_cell_value) = self.current_code_cell.clone() { - code_cell_value - } else { - // this should only happen after an internal logic error - crate::util::dbgjs( - "Expected current_code_cell to be defined in transaction::code_cell_error", - ); - return; - }; - updated_code_cell_value.last_modified = date_string(); - let msg = ErrorMsg::PythonError(error_msg.clone().into()); - let span = line_number.map(|line_number| Span { - start: line_number as u32, - end: line_number as u32, - }); - let error = Error { span, msg }; - let result = CodeCellRunResult::Err { error }; - updated_code_cell_value.output = Some(CodeCellRunOutput { - std_out: None, - std_err: Some(error_msg), - result, - spill: false, - }); - update_code_cell_value( - grid_controller, - cell_ref, - Some(updated_code_cell_value), - &mut self.cells_to_compute, - &mut self.reverse_operations, - &mut self.summary, - ); - self.summary.code_cells_modified.insert(cell_ref.sheet); - self.waiting_for_async = None; - } - /// continues the calculate cycle after an async call - pub fn calculation_complete( - &mut self, - grid_controller: &mut GridController, - result: JsCodeResult, - ) { + pub fn after_calculation_async(&mut self, result: JsCodeResult) { + assert!( + self.transaction_in_progress, + "Expected transaction_in_progress in after_calculation_async" + ); if self.complete { panic!("Transaction is already complete"); } - let (language, code_string) = - if let Some(old_code_cell_value) = self.current_code_cell.clone() { - ( - old_code_cell_value.language, - old_code_cell_value.code_string, - ) - } else { - panic!("Expected current_code_cell to be defined in transaction::complete"); - }; + + let old_code_cell_value = self.current_sheet_pos.and_then(|code_cell_sheet_pos| { + self.grid() + .sheet_from_id(code_cell_sheet_pos.sheet_id) + .get_code_cell(code_cell_sheet_pos.into()) + .cloned() + }); + assert!( + old_code_cell_value.is_some(), + "Expected old_code_cell_value to be defined" + ); + let old_code_cell_value = old_code_cell_value.unwrap(); + match self.waiting_for_async { None => { // this should only occur after an internal logic error @@ -209,29 +109,22 @@ impl TransactionInProgress { Some(waiting_for_async) => { match waiting_for_async { CodeCellLanguage::Python => { - let cell_ref = if let Some(sheet_pos) = self.current_cell_ref { + let sheet_pos = if let Some(sheet_pos) = self.current_sheet_pos { sheet_pos } else { panic!( "Expected current_sheet_pos to be defined in transaction::complete" ); }; - let sheet = grid_controller.grid_mut().sheet_mut_from_id(cell_ref.sheet); - let updated_code_cell_value = result.into_code_cell_value( - sheet, - cell_ref, - language, - code_string, - &self.cells_accessed, - &mut self.reverse_operations, + let updated_code_cell_value = self.js_code_result_to_code_cell_value( + result, + sheet_pos, + old_code_cell_value.language, + old_code_cell_value.code_string, ); - if update_code_cell_value( - grid_controller, - cell_ref, - Some(updated_code_cell_value), - &mut self.cells_to_compute, - &mut self.reverse_operations, - &mut self.summary, + if self.update_code_cell_value( + sheet_pos, + Some(updated_code_cell_value.clone()), ) { // clear cells_accessed self.cells_accessed.clear(); @@ -245,106 +138,109 @@ impl TransactionInProgress { } } // continue the compute loop after a successful async call - self.loop_compute(grid_controller); + self.loop_compute(); } - /// checks the next cell in the cells_to_compute and computes it - /// returns true if an async call is made or the compute cycle is completed - fn compute(&mut self, grid_controller: &mut GridController) { - while let Some(region) = self.cells_updated.shift_remove_index(0) { - if let Some(dependent_cells) = grid_controller.get_dependent_cells_for_region(region) { - self.cells_to_compute.extend(dependent_cells); + pub(super) fn code_cell_sheet_error(&mut self, error_msg: String, line_number: Option) { + let sheet_pos = if let Some(sheet_pos) = self.current_sheet_pos { + sheet_pos + } else { + // this should only happen after an internal logic error + crate::util::dbgjs( + "Expected current_sheet_pos to be defined in transaction::code_cell_error", + ); + return; + }; + let update_code_cell_value = self.current_sheet_pos.and_then(|code_cell_sheet_pos| { + self.grid() + .sheet_from_id(code_cell_sheet_pos.sheet_id) + .get_code_cell(code_cell_sheet_pos.into()) + .cloned() + }); + match update_code_cell_value { + None => { + // this should only happen after an internal logic error + crate::util::dbgjs( + "Expected current_code_cell to be defined in transaction::code_cell_error", + ); } - } - - if let Some(cell_ref) = self.cells_to_compute.shift_remove_index(0) { - // todo: this would be a good place to check for cycles - // add all dependent cells to the cells_to_compute - if let Some(dependent_cells) = grid_controller.get_dependent_cells(cell_ref) { - #[cfg(feature = "show-operations")] - dependent_cells.iter().for_each(|cell_ref| { - let sheet = grid_controller.sheet(cell_ref.sheet); - if let Some(pos) = sheet.cell_ref_to_pos(*cell_ref) { - crate::util::dbgjs(format!("[Adding Dependent Cell] {:?}", pos)); - } + Some(update_code_cell_value) => { + let mut code_cell_value = update_code_cell_value.clone(); + code_cell_value.last_modified = date_string(); + let msg = ErrorMsg::PythonError(error_msg.clone().into()); + let span = line_number.map(|line_number| Span { + start: line_number as u32, + end: line_number as u32, }); - - self.cells_to_compute.extend(dependent_cells); - } - - let sheet = grid_controller.grid().sheet_from_id(cell_ref.sheet); - if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { - // find which cells have code. Run the code and update the cells. - // add the updated cells to the cells_to_compute - - if let Some(code_cell) = sheet.get_code_cell(pos) { - #[cfg(feature = "show-operations")] - crate::util::dbgjs(format!( - "[Compute] {:?} ({} remaining)", - pos, - self.cells_to_compute.len() - )); - self.current_cell_ref = Some(cell_ref); - self.current_code_cell = Some(code_cell.clone()); - let code_string = code_cell.code_string.clone(); - let language = code_cell.language; - match language { - CodeCellLanguage::Python => { - // python is run async so we exit the compute cycle and wait for TS to restart the transaction - if !cfg!(test) { - let result = crate::wasm_bindings::js::runPython(code_string); - - // run python will return false if python is not loaded (this can be generalized if we need to return a different error) - if result == JsValue::FALSE { - self.code_cell_sheet_error( - grid_controller, - "Python interpreter not yet loaded (please run again)" - .to_string(), - None, - ); - return; - } - } - self.waiting_for_async = Some(language); - self.has_async = true; - } - CodeCellLanguage::Formula => { - self.eval_formula( - grid_controller, - code_string.clone(), - language, - pos, - cell_ref, - sheet.id, - ); - } - _ => { - crate::util::dbgjs(format!( - "Compute language {} not supported in compute.rs", - language - )); - } - } - } + let error = Error { span, msg }; + let result = CodeCellRunResult::Err { error }; + code_cell_value.output = Some(CodeCellRunOutput { + std_out: None, + std_err: Some(error_msg), + result, + spill: false, + }); + self.update_code_cell_value(sheet_pos, Some(code_cell_value)); + self.summary.code_cells_modified.insert(sheet_pos.sheet_id); + self.waiting_for_async = None; } } } -} - -impl From<&TransactionInProgress> for Transaction { - fn from(val: &TransactionInProgress) -> Self { - Transaction { - ops: val.reverse_operations.clone().into_iter().rev().collect(), - cursor: val.cursor.clone(), - } - } -} -impl From for TransactionInProgress { - fn from(val: Transaction) -> Self { - TransactionInProgress { - cursor: val.cursor, - ..Default::default() + // Returns a CodeCellValue from a JsCodeResult. + // This requires access to GridController to update the grid and create operations. + pub(super) fn js_code_result_to_code_cell_value( + &mut self, + js_code_result: JsCodeResult, + start: SheetPos, + language: CodeCellLanguage, + code_string: String, + ) -> CodeCellValue { + let sheet = self.grid_mut().sheet_mut_from_id(start.sheet_id); + let result = if js_code_result.success() { + CodeCellRunResult::Ok { + output_value: if let Some(array_output) = js_code_result.array_output() { + let (array, ops) = Array::from_string_list(start.into(), sheet, array_output); + self.reverse_operations.extend(ops); + if let Some(array) = array { + Value::Array(array) + } else { + Value::Single("".into()) + } + } else if let Some(output_value) = js_code_result.output_value() { + let (cell_value, ops) = + CellValue::from_string(&output_value, start.into(), sheet); + self.reverse_operations.extend(ops); + Value::Single(cell_value) + } else { + unreachable!() + }, + cells_accessed: self.cells_accessed.clone().into_iter().collect(), + } + } else { + let error_msg = js_code_result + .error_msg() + .unwrap_or_else(|| "Unknown Python Error".into()); + let msg = ErrorMsg::PythonError(error_msg.into()); + let span = js_code_result.line_number().map(|line_number| Span { + start: line_number, + end: line_number, + }); + CodeCellRunResult::Err { + error: Error { span, msg }, + } + }; + CodeCellValue { + language, + code_string, + formatted_code_string: js_code_result.formatted_code().clone(), + output: Some(CodeCellRunOutput { + std_out: js_code_result.input_python_std_out(), + std_err: js_code_result.error_msg(), + result, + spill: false, + }), + last_modified: date_string(), } } } @@ -357,13 +253,13 @@ mod test { use crate::{ controller::{ - operation::Operation, + execution::TransactionType, + operations::operation::Operation, transaction_types::{CellForArray, JsCodeResult, JsComputeGetCells}, - transactions::TransactionType, GridController, }, - grid::{CodeCellLanguage, CodeCellValue}, - CellValue, Pos, + grid::{CodeCellLanguage, CodeCellRunOutput, CodeCellValue}, + Array, ArraySize, CellValue, Pos, SheetPos, Value, }; fn setup_python( @@ -372,16 +268,19 @@ mod test { cell_value: CellValue, ) -> GridController { let mut gc = gc.unwrap_or_default(); - let sheet_ids = gc.sheet_ids(); - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_ids[0]); + let sheet_id = gc.sheet_ids()[0]; + let sheet = gc.grid_mut().sheet_mut_from_id(sheet_id); let cell_value_pos = Pos { x: 0, y: 0 }; - let code_cell_pos = Pos { x: 1, y: 0 }; + let code_cell_pos = SheetPos { + x: 1, + y: 0, + sheet_id, + }; sheet.set_cell_value(cell_value_pos, cell_value.clone()); - let cell_ref = sheet.get_or_create_cell_ref(code_cell_pos); gc.set_in_progress_transaction( vec![Operation::SetCellCode { - cell_ref, + sheet_pos: code_cell_pos, code_cell_value: Some(CodeCellValue { language: CodeCellLanguage::Python, code_string: code_string.clone(), @@ -392,20 +291,19 @@ mod test { }], None, true, - crate::controller::transactions::TransactionType::Normal, + TransactionType::User, ); // code should be at (1, 0) let code_cell = gc - .js_get_code_string(sheet_ids[0].to_string(), &code_cell_pos.clone()) + .js_get_code_string(sheet_id.to_string(), &code_cell_pos.into()) .unwrap(); assert_eq!(code_cell.code_string(), code_string); assert_eq!(code_cell.language(), CodeCellLanguage::Python); // pending transaction - let transaction = gc.get_transaction_in_progress().unwrap(); - assert!(!transaction.complete); - assert_eq!(transaction.cells_to_compute.len(), 0); + assert!(!gc.complete); + assert_eq!(gc.cells_to_compute.len(), 0); // pull out the code cell let cells_for_array = gc.calculation_get_cells(JsComputeGetCells::new( @@ -568,6 +466,7 @@ mod test { let code_string = "asdf".to_string(); let error = "NameError on line 1: name 'asdf' is not defined".to_string(); let cell_value = CellValue::Blank; + let mut gc = setup_python(Some(gc), code_string.clone(), cell_value); let sheet_id = gc.sheet_ids()[0]; @@ -601,14 +500,18 @@ mod test { #[test] fn test_execute_operation_set_cell_values_formula() { let mut gc = GridController::new(); - let sheet_ids = gc.sheet_ids(); - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_ids[0]); + let sheet_id = gc.sheet_ids()[0]; + let sheet = gc.grid_mut().sheet_mut_from_id(sheet_id); - sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Number(BigDecimal::from(10))); - let cell_ref = sheet.get_or_create_cell_ref(Pos { x: 1, y: 0 }); + let _ = sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Number(BigDecimal::from(10))); + let sheet_pos = SheetPos { + x: 1, + y: 0, + sheet_id, + }; gc.set_in_progress_transaction( vec![Operation::SetCellCode { - cell_ref, + sheet_pos, code_cell_value: Some(CodeCellValue { language: CodeCellLanguage::Formula, code_string: "A0 + 1".to_string(), @@ -619,11 +522,11 @@ mod test { }], None, true, - crate::controller::transactions::TransactionType::Normal, + TransactionType::User, ); - assert!(gc.get_transaction_in_progress().is_none()); + assert!(!gc.transaction_in_progress); - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_ids[0]); + let sheet = gc.grid_mut().sheet_mut_from_id(sheet_id); assert!(sheet.get_code_cell(Pos { x: 1, y: 0 }).is_some()); let code_cell = sheet.get_code_cell(Pos { x: 1, y: 0 }).unwrap(); assert_eq!(code_cell.code_string, "A0 + 1".to_string()); @@ -632,22 +535,30 @@ mod test { Some(CellValue::Number(11.into())) ); - let cell_ref = sheet.get_or_create_cell_ref(Pos { x: 0, y: 0 }); - let dependencies = gc.get_dependent_cells(cell_ref).unwrap().clone(); + let sheet_pos = SheetPos { + x: 0, + y: 0, + sheet_id, + }; + let dependencies = gc.get_dependent_cells(sheet_pos).unwrap().clone(); assert_eq!(dependencies.len(), 1); } #[test] fn test_multiple_formula() { let mut gc = GridController::new(); - let sheet_ids = gc.sheet_ids(); - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_ids[0]); + let sheet_id = gc.sheet_ids()[0]; + let sheet = gc.grid_mut().sheet_mut_from_id(sheet_id); - sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Number(BigDecimal::from(10))); - let cell_ref = sheet.get_or_create_cell_ref(Pos { x: 1, y: 0 }); + let _ = sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Number(BigDecimal::from(10))); + let sheet_pos = SheetPos { + x: 1, + y: 0, + sheet_id, + }; gc.set_in_progress_transaction( vec![Operation::SetCellCode { - cell_ref, + sheet_pos, code_cell_value: Some(CodeCellValue { language: CodeCellLanguage::Formula, code_string: "A0 + 1".to_string(), @@ -658,14 +569,17 @@ mod test { }], None, true, - crate::controller::transactions::TransactionType::Normal, + TransactionType::User, ); - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_ids[0]); - let cell_ref = sheet.get_or_create_cell_ref(Pos { x: 2, y: 0 }); + let sheet_pos = SheetPos { + x: 2, + y: 0, + sheet_id, + }; gc.set_in_progress_transaction( vec![Operation::SetCellCode { - cell_ref, + sheet_pos, code_cell_value: Some(CodeCellValue { language: CodeCellLanguage::Formula, code_string: "B0 + 1".to_string(), @@ -676,10 +590,10 @@ mod test { }], None, true, - TransactionType::Normal, + TransactionType::User, ); - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_ids[0]); + let sheet = gc.grid_mut().sheet_mut_from_id(sheet_id); assert!(sheet.get_code_cell(Pos { x: 2, y: 0 }).is_some()); let code_cell = sheet.get_code_cell(Pos { x: 2, y: 0 }).unwrap(); assert_eq!(code_cell.code_string, "B0 + 1".to_string()); @@ -692,19 +606,22 @@ mod test { Some(CellValue::Number(12.into())) ); - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_ids[0]); - let cell_ref = sheet.get_or_create_cell_ref(Pos { x: 0, y: 0 }); + let sheet_pos = SheetPos { + x: 0, + y: 0, + sheet_id, + }; gc.set_in_progress_transaction( vec![Operation::SetCellValues { - region: cell_ref.into(), + sheet_rect: sheet_pos.into(), values: CellValue::Number(1.into()).into(), }], None, true, - TransactionType::Normal, + TransactionType::User, ); - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_ids[0]); + let sheet = gc.grid_mut().sheet_mut_from_id(sheet_id); assert_eq!( sheet.get_cell_value(Pos { x: 1, y: 0 }), Some(CellValue::Number(2.into())) @@ -718,13 +635,23 @@ mod test { #[test] fn test_deleting_to_trigger_compute() { let mut gc = GridController::new(); - let sheet_ids = gc.sheet_ids(); - let sheet_id = sheet_ids[0]; + let sheet_id = gc.sheet_ids()[0]; - gc.set_cell_value(sheet_id, Pos { x: 0, y: 0 }, "10".into(), None); + gc.set_cell_value( + SheetPos { + x: 0, + y: 0, + sheet_id, + }, + "10".into(), + None, + ); gc.set_cell_code( - sheet_id, - Pos { x: 0, y: 1 }, + SheetPos { + x: 0, + y: 1, + sheet_id, + }, CodeCellLanguage::Formula, "A0 + 1".into(), None, @@ -736,7 +663,15 @@ mod test { Some(CellValue::Number(11.into())) ); - gc.set_cell_value(sheet_id, Pos { x: 0, y: 0 }, "".into(), None); + gc.set_cell_value( + SheetPos { + x: 0, + y: 0, + sheet_id, + }, + "".into(), + None, + ); let sheet = gc.sheet(sheet_id); assert_eq!( sheet.get_cell_value(Pos { x: 0, y: 1 }), @@ -760,10 +695,106 @@ mod test { Some(true), ); - gc.calculation_complete(result); + gc.after_calculation_async(result); + + assert!(gc.complete); + assert_eq!(gc.cells_to_compute.len(), 0); + } + + #[test] + fn test_js_code_result_to_code_cell_value_single() { + let mut gc = GridController::new(); + let sheet_id = gc.sheet_ids()[0]; + let result = JsCodeResult::new_from_rust( + true, + None, + None, + None, + Some("$12".into()), + None, + None, + None, + ); + + let sheet_pos = SheetPos { + x: 0, + y: 0, + sheet_id, + }; + assert_eq!( + gc.js_code_result_to_code_cell_value( + result, + sheet_pos, + CodeCellLanguage::Python, + "".into(), + ) + .output, + Some(CodeCellRunOutput { + std_out: None, + std_err: None, + result: crate::grid::CodeCellRunResult::Ok { + output_value: Value::Single(CellValue::Number(12.into())), + cells_accessed: HashSet::new() + }, + spill: false, + }), + ); + } + + #[test] + fn test_js_code_result_to_code_cell_value_array() { + let mut gc = GridController::new(); + let sheet_id = gc.sheet_ids()[0]; + let array_output: Vec> = vec![ + vec!["$1.1".into(), "20%".into()], + vec!["3".into(), "Hello".into()], + ]; + let result = JsCodeResult::new_from_rust( + true, + None, + None, + None, + None, + Some(array_output), + None, + None, + ); - let transaction = gc.get_transaction_in_progress().unwrap(); - assert!(transaction.complete); - assert_eq!(transaction.cells_to_compute.len(), 0); + let sheet_pos = SheetPos { + x: 0, + y: 0, + sheet_id, + }; + let mut array = Array::new_empty(ArraySize::new(2, 2).unwrap()); + let _ = array.set( + 0, + 0, + CellValue::Number(BigDecimal::from_str("1.1").unwrap()), + ); + let _ = array.set( + 1, + 0, + CellValue::Number(BigDecimal::from_str("0.2").unwrap()), + ); + let _ = array.set(0, 1, CellValue::Number(BigDecimal::from_str("3").unwrap())); + let _ = array.set(1, 1, CellValue::Text("Hello".into())); + assert_eq!( + gc.js_code_result_to_code_cell_value( + result, + sheet_pos, + CodeCellLanguage::Python, + "".into(), + ) + .output, + Some(CodeCellRunOutput { + std_out: None, + std_err: None, + result: crate::grid::CodeCellRunResult::Ok { + output_value: Value::Array(array), + cells_accessed: HashSet::new() + }, + spill: false, + }), + ); } } diff --git a/quadratic-core/src/controller/execution/control_transaction.rs b/quadratic-core/src/controller/execution/control_transaction.rs new file mode 100644 index 0000000000..57e9d0db00 --- /dev/null +++ b/quadratic-core/src/controller/execution/control_transaction.rs @@ -0,0 +1,309 @@ +use core::panic; +use std::collections::HashSet; + +use crate::{ + controller::{ + operations::operation::Operation, + transaction_summary::{TransactionSummary, CELL_SHEET_HEIGHT, CELL_SHEET_WIDTH}, + transaction_types::{CellsForArray, JsCodeResult, JsComputeGetCells}, + }, + Pos, +}; +use indexmap::IndexSet; + +use super::{GridController, TransactionType}; + +impl GridController { + // loop compute cycle until complete or an async call is made + pub(super) fn loop_compute(&mut self) { + loop { + self.compute(); + if self.waiting_for_async.is_some() { + break; + } + if self.cells_to_compute.is_empty() { + self.complete = true; + self.transaction_in_progress = false; + self.summary.save = true; + if self.has_async { + self.finalize_transaction(); + } + break; + } + } + } + + /// executes a set of operations + fn transact(&mut self, operations: Vec, compute: bool) { + for op in operations.iter() { + if cfg!(feature = "show-operations") { + crate::util::dbgjs(&format!("[Operation] {:?}", op.to_string())); + } + + self.execute_operation(op.clone(), compute); + } + } + + /// Creates and runs a new Transaction + /// + /// Description + /// * `compute` triggers the computation cycle + fn start_transaction( + &mut self, + operations: Vec, + cursor: Option, + compute: bool, + transaction_type: TransactionType, + ) { + if self.transaction_in_progress { + panic!("Expected no transaction in progress"); + } + self.transaction_in_progress = true; + self.reverse_operations = vec![]; + self.cells_updated = IndexSet::new(); + self.cells_to_compute = IndexSet::new(); + self.cursor = cursor; + self.cells_accessed = HashSet::new(); + self.summary = TransactionSummary::default(); + self.sheets_with_changed_bounds = HashSet::new(); + self.transaction_type = transaction_type; + self.has_async = false; + self.current_sheet_pos = None; + self.waiting_for_async = None; + self.complete = false; + self.forward_operations = vec![]; + + // apply operations + self.transact(operations, compute); + + // run computations + if compute { + self.loop_compute(); + } else { + self.complete = true; + self.transaction_in_progress = false; + } + } + + pub(super) fn finalize_transaction(&mut self) { + match self.transaction_type { + TransactionType::User => { + self.undo_stack.push(self.to_transaction()); + self.redo_stack.clear(); + } + TransactionType::Undo => { + self.redo_stack.push(self.to_transaction()); + } + TransactionType::Redo => { + self.undo_stack.push(self.to_transaction()); + } + TransactionType::Multiplayer => (), + TransactionType::Unset => panic!("Expected a transaction type"), + } + } + + pub fn set_in_progress_transaction( + &mut self, + operations: Vec, + cursor: Option, + compute: bool, + transaction_type: TransactionType, + ) -> TransactionSummary { + assert!( + !self.transaction_in_progress, + "Expected no transaction in progress in set_in_progress_transaction" + ); + self.start_transaction(operations, cursor, compute, transaction_type); + let mut summary = self.prepare_transaction_summary(); + self.transaction_updated_bounds(); + + if self.complete { + summary.save = true; + self.finalize_transaction(); + } + summary + } + + pub fn calculation_complete(&mut self, result: JsCodeResult) -> TransactionSummary { + assert!(self.transaction_in_progress); + let cancel_compute = result.cancel_compute.unwrap_or(false); + + if cancel_compute { + self.clear_cells_to_compute(); + self.loop_compute(); + } + + self.after_calculation_async(result); + + self.transaction_updated_bounds(); + if self.complete { + self.summary.save = true; + self.finalize_transaction(); + } + self.prepare_transaction_summary() + } + + /// This is used to get cells during a TS-controlled async calculation + pub fn calculation_get_cells(&mut self, get_cells: JsComputeGetCells) -> Option { + assert!(self.transaction_in_progress); + self.get_cells(get_cells) + } + + pub fn received_transaction(&mut self, transaction: String) -> TransactionSummary { + let operations: Vec = if let Ok(operations) = serde_json::from_str(&transaction) + { + operations + } else { + return TransactionSummary::default(); + }; + + self.apply_received_transaction(operations) + } + + pub fn apply_received_transaction(&mut self, operations: Vec) -> TransactionSummary { + self.start_transaction(operations, None, false, TransactionType::Multiplayer); + self.transaction_updated_bounds(); + let mut summary = self.prepare_transaction_summary(); + summary.generate_thumbnail = false; + summary.forward_operations = None; + summary.save = false; + summary + } +} + +#[derive(Debug, PartialEq)] +pub struct CellHash(String); + +impl CellHash { + pub fn get(&self) -> String { + self.0.clone() + } +} + +impl From for CellHash { + fn from(pos: Pos) -> Self { + let hash_width = CELL_SHEET_WIDTH as f64; + let hash_height = CELL_SHEET_HEIGHT as f64; + let cell_hash_x = (pos.x as f64 / hash_width).floor() as i64; + let cell_hash_y = (pos.y as f64 / hash_height).floor() as i64; + let cell_hash = format!("{},{}", cell_hash_x, cell_hash_y); + + CellHash(cell_hash) + } +} + +#[cfg(test)] +mod tests { + use crate::{grid::GridBounds, Array, CellValue, Pos, Rect, SheetPos, SheetRect}; + + use super::*; + + fn add_cell_value(sheet_pos: SheetPos, value: CellValue) -> Operation { + let sheet_rect = SheetRect::single_sheet_pos(sheet_pos); + + Operation::SetCellValues { + sheet_rect, + values: Array::from(value), + } + } + + fn get_operations(gc: &mut GridController) -> (Operation, Operation) { + let sheet_id = gc.sheet_ids()[0]; + let sheet_pos = SheetPos::from((0, 0, sheet_id)); + let value = CellValue::Text("test".into()); + let operation = add_cell_value(sheet_pos, value); + let operation_undo = add_cell_value(sheet_pos, CellValue::Blank); + + (operation, operation_undo) + } + + #[test] + fn test_transactions_finalize_transaction() { + let mut gc = GridController::new(); + let (operation, operation_undo) = get_operations(&mut gc); + + // TransactionType::Normal + gc.start_transaction(vec![operation.clone()], None, false, TransactionType::User); + gc.finalize_transaction(); + + assert_eq!(gc.undo_stack.len(), 1); + assert_eq!(gc.redo_stack.len(), 0); + assert_eq!(vec![operation_undo.clone()], gc.undo_stack[0].operations); + + // TransactionType::Undo + gc.start_transaction(vec![], None, false, TransactionType::Undo); + gc.finalize_transaction(); + + assert_eq!(gc.undo_stack.len(), 1); + assert_eq!(gc.redo_stack.len(), 1); + assert_eq!(vec![operation_undo.clone()], gc.undo_stack[0].operations); + assert_eq!(gc.redo_stack[0].operations.len(), 0); + + // TransactionType::Redo + gc.start_transaction(vec![], None, false, TransactionType::Redo); + gc.finalize_transaction(); + + assert_eq!(gc.undo_stack.len(), 2); + assert_eq!(gc.redo_stack.len(), 1); + assert_eq!(vec![operation_undo.clone()], gc.undo_stack[0].operations); + assert_eq!(gc.redo_stack[0].operations.len(), 0); + } + + #[test] + fn test_transactions_undo_redo() { + let mut gc = GridController::new(); + let (operation, operation_undo) = get_operations(&mut gc); + + assert!(!gc.has_undo()); + assert!(!gc.has_redo()); + + gc.set_in_progress_transaction(vec![operation.clone()], None, false, TransactionType::User); + assert!(gc.has_undo()); + assert!(!gc.has_redo()); + assert_eq!(vec![operation_undo.clone()], gc.undo_stack[0].operations); + + // undo + gc.undo(None); + assert!(!gc.has_undo()); + assert!(gc.has_redo()); + + // redo + gc.redo(None); + assert!(gc.has_undo()); + assert!(!gc.has_redo()); + } + + #[test] + fn test_transactions_transaction_summary() { + let mut gc = GridController::new(); + assert_eq!( + gc.prepare_transaction_summary(), + TransactionSummary::default() + ); + } + + #[test] + fn test_transactions_updated_bounds_in_transaction() { + let mut gc = GridController::new(); + let (operation, _) = get_operations(&mut gc); + + assert_eq!(gc.grid().sheets()[0].bounds(true), GridBounds::Empty); + + gc.set_in_progress_transaction(vec![operation], None, true, TransactionType::User); + gc.transaction_updated_bounds(); + + let expected = GridBounds::NonEmpty(Rect::single_pos((0, 0).into())); + assert_eq!(gc.grid().sheets()[0].bounds(true), expected); + } + + #[test] + fn test_transactions_cell_hash() { + let hash = "test".to_string(); + let cell_hash = CellHash(hash.clone()); + assert_eq!(cell_hash.get(), hash); + + let pos = Pos::from((0, 0)); + let cell_hash = CellHash::from(pos); + assert_eq!(cell_hash, CellHash("0,0".into())); + } +} diff --git a/quadratic-core/src/controller/execution/eval_formula.rs b/quadratic-core/src/controller/execution/eval_formula.rs new file mode 100644 index 0000000000..b19b516eaf --- /dev/null +++ b/quadratic-core/src/controller/execution/eval_formula.rs @@ -0,0 +1,63 @@ +use crate::{ + controller::GridController, + formulas::{parse_formula, Ctx}, + grid::{CodeCellLanguage, CodeCellRunOutput, CodeCellRunResult, CodeCellValue}, + SheetPos, +}; + +impl GridController { + pub(super) fn eval_formula( + &mut self, + code_string: String, + language: CodeCellLanguage, + sheet_pos: SheetPos, + ) { + let mut ctx = Ctx::new(self.grid(), sheet_pos); + match parse_formula(&code_string, sheet_pos.into()) { + Ok(parsed) => { + match parsed.eval(&mut ctx) { + Ok(value) => { + self.cells_accessed = ctx.cells_accessed; + let updated_code_cell_value = CodeCellValue { + language, + code_string, + formatted_code_string: None, + output: Some(CodeCellRunOutput { + std_out: None, + std_err: None, + result: CodeCellRunResult::Ok { + output_value: value, + cells_accessed: self + .cells_accessed + .clone() + .into_iter() + .collect(), + }, + spill: false, + }), + // todo + last_modified: String::new(), + }; + if self.update_code_cell_value(sheet_pos, Some(updated_code_cell_value)) { + // clears cells_accessed + self.cells_accessed.clear(); + } + } + Err(error) => { + let msg = error.msg.to_string(); + let line_number = error.span.map(|span| span.start as i64); + self.code_cell_sheet_error( + msg, + // todo: span should be multiline + line_number, + ); + } + } + } + Err(e) => { + let msg = e.to_string(); + self.code_cell_sheet_error(msg, None); + } + } + } +} diff --git a/quadratic-core/src/controller/execution/execute_operation.rs b/quadratic-core/src/controller/execution/execute_operation.rs new file mode 100644 index 0000000000..f5d00ec01d --- /dev/null +++ b/quadratic-core/src/controller/execution/execute_operation.rs @@ -0,0 +1,481 @@ +use crate::grid::formatting::CellFmtArray; +use crate::{grid::*, Array, CellValue, SheetPos}; + +use crate::controller::operations::operation::Operation; +use crate::controller::GridController; + +impl GridController { + /// Executes the given operation. + pub fn execute_operation(&mut self, op: Operation, compute: bool) { + match op { + Operation::SetCellValues { sheet_rect, values } => { + // todo: this should be moved to the update_bounds function + self.sheets_with_changed_bounds.insert(sheet_rect.sheet_id); + + let sheet = self.grid.sheet_mut_from_id(sheet_rect.sheet_id); + + let size = sheet_rect.size(); + let old_values = sheet_rect + .iter() + .zip(values.clone().into_cell_values_vec()) + .map(|(sheet_pos, value)| { + let old_value = sheet.set_cell_value(sheet_pos.into(), value); + if old_value + .as_ref() + .is_some_and(|cell_value| cell_value.is_html()) + { + self.summary.html.insert(sheet_pos.sheet_id); + } + old_value + }) + .map(|old_value| old_value.unwrap_or(CellValue::Blank)) + .collect(); + self.cells_updated.insert(sheet_rect); + + let old_values = Array::new_row_major(size, old_values) + .expect("error constructing array of old values for SetCells operation"); + + self.add_cell_sheets_modified_rect(&sheet_rect); + + // todo: this should be moved to the code_cell operations function + // check if override any code cells + let sheet = self.grid.sheet_from_id(sheet_rect.sheet_id); + let code_cells_to_delete = sheet + .code_cells + .iter() + .filter_map(|(pos, _)| { + let possible_delete = pos.to_sheet_pos(sheet.id); + if sheet_rect.contains(possible_delete) { + Some(possible_delete) + } else { + None + } + }) + .collect::>(); + + // todo: this should be moved to the code_cell operations function + // remove the code cells + let sheet_id = sheet.id; + for sheet_pos in code_cells_to_delete { + let sheet = self.grid.sheet_mut_from_id(sheet_id); + let old_value = sheet.set_code_cell_value(sheet_pos.into(), None); + self.fetch_code_cell_difference(sheet_pos, old_value.clone(), None); + self.reverse_operations.push(Operation::SetCellCode { + sheet_pos, + code_cell_value: old_value, + }); + } + + // todo: this should be moved to the spills operations function + // check for changes in spills + for sheet_pos in sheet_rect.iter() { + let sheet = self.grid.sheet_from_id(sheet_pos.sheet_id); + // if there is a value, check if it caused a spill + if sheet.get_cell_value(sheet_pos.into()).is_some() { + self.check_spill(sheet_pos); + } else { + // otherwise check if it released a spill + self.update_code_cell_value_if_spill_error_released(sheet_pos); + } + } + + // todo: this should be removed (forward operations should be generically added in the execute_operations function) + self.forward_operations + .push(Operation::SetCellValues { sheet_rect, values }); + + self.summary.generate_thumbnail = + self.summary.generate_thumbnail || self.thumbnail_dirty_sheet_rect(sheet_rect); + + self.reverse_operations.push(Operation::SetCellValues { + sheet_rect, + values: old_values, + }); + } + Operation::SetCellCode { + sheet_pos, + code_cell_value, + } => { + let is_code_cell_empty = code_cell_value.is_none(); + let sheet_id = sheet_pos.sheet_id; + + self.sheets_with_changed_bounds.insert(sheet_id); + + let sheet = self.grid.sheet_mut_from_id(sheet_id); + + // todo: all spill calculation should be moved to the code_cell operation function + let old_spill = sheet.get_spill(sheet_pos.into()); + let old_code_cell_value = sheet.get_code_cell(sheet_pos.into()).cloned(); + let final_code_cell_value; + + // for compute, we keep the original cell output to avoid flashing of output (since values will be overridden once computation is complete) + let sheet = self.grid.sheet_mut_from_id(sheet_id); + if compute { + if let Some(code_cell_value) = code_cell_value { + let updated_code_cell_value = + if let Some(old_code_cell_value) = &old_code_cell_value { + let mut updated_code_cell_value = code_cell_value.clone(); + updated_code_cell_value.output = old_code_cell_value.output.clone(); + updated_code_cell_value + } else { + code_cell_value + }; + sheet.set_code_cell_value( + sheet_pos.into(), + Some(updated_code_cell_value.clone()), + ); + final_code_cell_value = Some(updated_code_cell_value); + } else { + sheet.set_code_cell_value(sheet_pos.into(), code_cell_value); + self.fetch_code_cell_difference( + sheet_pos, + old_code_cell_value.clone(), + None, + ); + let sheet = self.grid.sheet_mut_from_id(sheet_id); + sheet.set_code_cell_value(sheet_pos.into(), None); + final_code_cell_value = None; + } + self.cells_to_compute.insert(sheet_pos); + } else { + // need to update summary (cells_to_compute will be ignored) + self.fetch_code_cell_difference( + sheet_pos, + old_code_cell_value.clone(), + code_cell_value.clone(), + ); + let sheet = self.grid.sheet_mut_from_id(sheet_id); + sheet.set_code_cell_value(sheet_pos.into(), code_cell_value.clone()); + final_code_cell_value = code_cell_value; + } + + // TODO(ddimaria): resolve comment from @HactarCE: + // + // Can we use SheetPos instead of CellSheetsModified? I'd like + // to avoid using String for sheet IDs as much as possible. If + // it's needed for JS interop, then let's impl Serialize and + // Deserialize on SheetId to make it serialize as a string. + self.add_cell_sheets_modified_rect(&sheet_pos.into()); + self.summary.code_cells_modified.insert(sheet_id); + + // check if a new code_cell causes a spill error in another code cell + if old_code_cell_value.is_none() && !is_code_cell_empty { + if let Some(old_spill) = old_spill { + if old_spill.to_sheet_pos(sheet_id) != sheet_pos { + self.set_spill_error(old_spill.to_sheet_pos(sheet_id)); + } + } + } + + // check if deleting a code cell releases a spill + if is_code_cell_empty { + self.update_code_cell_value_if_spill_error_released(sheet_pos); + } + self.forward_operations.push(Operation::SetCellCode { + sheet_pos, + code_cell_value: final_code_cell_value, + }); + self.reverse_operations.push(Operation::SetCellCode { + sheet_pos, + code_cell_value: old_code_cell_value, + }); + } + + Operation::SetCellFormats { sheet_rect, attr } => { + self.sheets_with_changed_bounds.insert(sheet_rect.sheet_id); + + if let CellFmtArray::FillColor(_) = attr { + self.summary.fill_sheets_modified.push(sheet_rect.sheet_id); + } + + // todo: this is too slow -- perhaps call this again when we have a better way of setting multiple formats within an array + // or when we get rid of CellRefs (which I think is the reason this is slow) + // summary.generate_thumbnail = + // summary.generate_thumbnail || self.thumbnail_dirty_region(region.clone()); + + let old_attr = match attr.clone() { + CellFmtArray::Align(align) => CellFmtArray::Align( + self.set_cell_formats_for_type::(&sheet_rect, align, true), + ), + CellFmtArray::Wrap(wrap) => CellFmtArray::Wrap( + self.set_cell_formats_for_type::(&sheet_rect, wrap, true), + ), + CellFmtArray::NumericFormat(num_fmt) => CellFmtArray::NumericFormat( + self.set_cell_formats_for_type::(&sheet_rect, num_fmt, true), + ), + CellFmtArray::NumericDecimals(num_decimals) => CellFmtArray::NumericDecimals( + self.set_cell_formats_for_type::( + &sheet_rect, + num_decimals, + true, + ), + ), + CellFmtArray::NumericCommas(num_commas) => CellFmtArray::NumericCommas( + self.set_cell_formats_for_type::( + &sheet_rect, + num_commas, + true, + ), + ), + CellFmtArray::Bold(bold) => CellFmtArray::Bold( + self.set_cell_formats_for_type::(&sheet_rect, bold, true), + ), + CellFmtArray::Italic(italic) => CellFmtArray::Italic( + self.set_cell_formats_for_type::(&sheet_rect, italic, true), + ), + CellFmtArray::TextColor(text_color) => CellFmtArray::TextColor( + self.set_cell_formats_for_type::(&sheet_rect, text_color, true), + ), + CellFmtArray::FillColor(fill_color) => { + self.summary.fill_sheets_modified.push(sheet_rect.sheet_id); + CellFmtArray::FillColor(self.set_cell_formats_for_type::( + &sheet_rect, + fill_color, + false, + )) + } + CellFmtArray::RenderSize(output_size) => { + self.summary.html.insert(sheet_rect.sheet_id); + CellFmtArray::RenderSize(self.set_cell_formats_for_type::( + &sheet_rect, + output_size, + false, + )) + } + }; + + // todo: remove + self.forward_operations + .push(Operation::SetCellFormats { sheet_rect, attr }); + + self.reverse_operations.push(Operation::SetCellFormats { + sheet_rect, + attr: old_attr, + }); + } + + Operation::SetBorders { + sheet_rect, + borders, + } => { + self.sheets_with_changed_bounds.insert(sheet_rect.sheet_id); + self.summary + .border_sheets_modified + .push(sheet_rect.sheet_id); + self.summary.generate_thumbnail = + self.summary.generate_thumbnail || self.thumbnail_dirty_sheet_rect(sheet_rect); + + let sheet = self.grid.sheet_mut_from_id(sheet_rect.sheet_id); + + let old_borders = sheet.set_region_borders(&sheet_rect.into(), borders.clone()); + + // should be removed + self.forward_operations.push(Operation::SetBorders { + sheet_rect, + borders, + }); + self.reverse_operations.push(Operation::SetBorders { + sheet_rect, + borders: old_borders, + }); + } + Operation::AddSheet { sheet } => { + // todo: need to handle the case where sheet.order overlaps another sheet order + // this may happen after (1) delete a sheet; (2) MP update w/an added sheet; and (3) undo the deleted sheet + let sheet_id = sheet.id; + self.grid + .add_sheet(Some(sheet.clone())) + .expect("duplicate sheet name"); + self.summary.sheet_list_modified = true; + self.summary.html.insert(sheet_id); + self.forward_operations.push(Operation::AddSheet { sheet }); + self.reverse_operations + .push(Operation::DeleteSheet { sheet_id }); + } + Operation::DeleteSheet { sheet_id } => { + let deleted_sheet = self.grid.remove_sheet(sheet_id); + self.summary.sheet_list_modified = true; + self.forward_operations + .push(Operation::DeleteSheet { sheet_id }); + self.reverse_operations.push(Operation::AddSheet { + sheet: deleted_sheet, + }); + } + Operation::ReorderSheet { target, order } => { + let old_first = self.grid.first_sheet_id(); + let sheet = self.grid.sheet_from_id(target); + let original_order = sheet.order.clone(); + self.grid.move_sheet(target, order.clone()); + self.summary.sheet_list_modified = true; + + if old_first != self.grid.first_sheet_id() { + self.summary.generate_thumbnail = true; + } + self.forward_operations + .push(Operation::ReorderSheet { target, order }); + self.reverse_operations.push(Operation::ReorderSheet { + target, + order: original_order, + }); + } + Operation::SetSheetName { sheet_id, name } => { + let sheet = self.grid.sheet_mut_from_id(sheet_id); + let old_name = sheet.name.clone(); + sheet.name = name.clone(); + self.summary.sheet_list_modified = true; + self.forward_operations + .push(Operation::SetSheetName { sheet_id, name }); + self.reverse_operations.push(Operation::SetSheetName { + sheet_id, + name: old_name, + }); + } + Operation::SetSheetColor { sheet_id, color } => { + let sheet = self.grid.sheet_mut_from_id(sheet_id); + let old_color = sheet.color.clone(); + sheet.color = color.clone(); + self.summary.sheet_list_modified = true; + self.forward_operations + .push(Operation::SetSheetColor { sheet_id, color }); + self.reverse_operations.push(Operation::SetSheetColor { + sheet_id, + color: old_color, + }); + } + + Operation::ResizeColumn { + sheet_id, + column, + new_size, + } => { + let sheet = self.grid.sheet_mut_from_id(sheet_id); + self.summary.offsets_modified.push(sheet.id); + let old_size = sheet.offsets.set_column_width(column, new_size); + self.summary.generate_thumbnail = self.summary.generate_thumbnail + || self.thumbnail_dirty_sheet_pos(SheetPos { + x: column, + y: 0, + sheet_id, + }); + self.forward_operations.push(Operation::ResizeColumn { + sheet_id, + column, + new_size, + }); + self.reverse_operations.push(Operation::ResizeColumn { + sheet_id, + column, + new_size: old_size, + }); + } + + Operation::ResizeRow { + sheet_id, + row, + new_size, + } => { + let sheet = self.grid.sheet_mut_from_id(sheet_id); + let old_size = sheet.offsets.set_row_height(row, new_size); + self.summary.offsets_modified.push(sheet.id); + self.summary.generate_thumbnail = self.summary.generate_thumbnail + || self.thumbnail_dirty_sheet_pos(SheetPos { + x: 0, + y: row, + sheet_id, + }); + self.forward_operations.push(Operation::ResizeRow { + sheet_id, + row, + new_size, + }); + self.reverse_operations.push(Operation::ResizeRow { + sheet_id, + row, + new_size: old_size, + }); + } + }; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn execute(gc: &mut GridController, operation: Operation) { + gc.transaction_in_progress = true; + gc.execute_operation(operation, false); + } + + #[test] + fn test_execute_operation_set_sheet_color() { + let mut gc = GridController::new(); + let sheet_id = gc.sheet_ids()[0]; + let color = Some("red".to_string()); + let operation = Operation::SetSheetColor { + sheet_id, + color: color.clone(), + }; + + assert_eq!( + format!("{:?}", operation), + format!( + "SetSheetColor {{ sheet_id: SheetId {{ id: {} }}, color: Some(\"red\") }}", + sheet_id + ) + ); + + execute(&mut gc, operation); + assert_eq!(gc.grid.sheets()[0].color, color); + } + + #[test] + fn test_execute_operation_resize_column() { + let mut gc = GridController::new(); + let sheet_id = gc.sheet_ids()[0]; + let x = 0; + let new_size = 100.0; + let operation = Operation::ResizeColumn { + sheet_id, + column: x, + new_size, + }; + + assert_eq!( + format!("{:?}", operation), + format!( + "ResizeColumn {{ sheet_id: SheetId {{ id: {} }}, column: {}, new_size: {:.1} }}", + sheet_id, x, new_size + ) + ); + + execute(&mut gc, operation); + let column_width = gc.grid.sheet_from_id(sheet_id).offsets.column_width(x); + assert_eq!(column_width, new_size); + } + + #[test] + fn test_execute_operation_resize_row() { + let mut gc = GridController::new(); + let sheet = &mut gc.grid_mut().sheets_mut()[0]; + let sheet_id = sheet.id; + let row = 0; + let new_size = 100.0; + let operation = Operation::ResizeRow { + sheet_id, + row, + new_size, + }; + + assert_eq!( + format!("{:?}", operation), + format!( + "ResizeRow {{ sheet_id: SheetId {{ id: {} }}, row: {}, new_size: {:.1} }}", + sheet_id, row, new_size + ) + ); + + execute(&mut gc, operation); + let row_height = gc.grid.sheets()[0].offsets.row_height(row); + assert_eq!(row_height, new_size); + } +} diff --git a/quadratic-core/src/computation/get_cells.rs b/quadratic-core/src/controller/execution/get_cells.rs similarity index 51% rename from quadratic-core/src/computation/get_cells.rs rename to quadratic-core/src/controller/execution/get_cells.rs index 724ec58dfe..2d8a61af23 100644 --- a/quadratic-core/src/computation/get_cells.rs +++ b/quadratic-core/src/controller/execution/get_cells.rs @@ -1,35 +1,17 @@ use std::collections::HashSet; -use crate::Pos; - use crate::controller::{ transaction_types::{CellsForArray, JsComputeGetCells}, GridController, }; -use crate::grid::CellRef; - -use super::TransactionInProgress; +use crate::SheetPos; -impl TransactionInProgress { +impl GridController { /// gets cells for use in async calculations - pub fn get_cells( - &mut self, - grid_controller: &mut GridController, - get_cells: JsComputeGetCells, - ) -> Option { + pub fn get_cells(&mut self, get_cells: JsComputeGetCells) -> Option { // ensure that the get_cells is not requesting a reference to itself - let (current_sheet, pos) = if let Some(current_cell_ref) = self.current_cell_ref { - let sheet = grid_controller.sheet(current_cell_ref.sheet); - let pos = if let Some(pos) = sheet.cell_ref_to_pos(current_cell_ref) { - pos - } else { - // this should only occur after an internal logic error - crate::util::dbgjs( - "Expected current_cell_ref's sheet to be defined in transaction::get_cells", - ); - return Some(CellsForArray::new(vec![], true)); - }; - (sheet, pos) + let (current_sheet, pos) = if let Some(current_sheet_pos) = self.current_sheet_pos { + (current_sheet_pos.sheet_id, current_sheet_pos.into()) } else { // this should only occur after an internal logic error crate::util::dbgjs( @@ -42,40 +24,36 @@ impl TransactionInProgress { // if sheet_name is None, use the sheet_id from the pos let sheet = sheet_name.clone().map_or_else( - || Some(current_sheet), - |sheet_name| grid_controller.grid().sheet_from_name(sheet_name), + || Some(self.grid().sheet_from_id(current_sheet)), + |sheet_name| self.grid().sheet_from_name(sheet_name), ); if let Some(sheet) = sheet { - // ensure there's not a cell reference in the get_cells request - if get_cells.rect().contains(pos) && sheet.id == current_sheet.id { + // ensure that the current cell ref is not in the get_cells request + if get_cells.rect().contains(pos) && sheet.id == current_sheet { // unable to find sheet by name, generate error let msg = if let Some(line_number) = get_cells.line_number() { format!("cell cannot reference itself at line {}", line_number) } else { "Sheet not found".to_string() }; - self.code_cell_sheet_error(grid_controller, msg, get_cells.line_number()); - self.loop_compute(grid_controller); + self.code_cell_sheet_error(msg, get_cells.line_number()); + self.loop_compute(); return Some(CellsForArray::new(vec![], true)); } let rect = get_cells.rect(); let array = sheet.cell_array(rect); - - let mut cells_accessed: HashSet = HashSet::new(); - while let Some(cell_ref) = self.cells_accessed.pop() { - cells_accessed.insert(cell_ref); - } + let mut cells_accessed: HashSet = HashSet::new(); let sheet_id = sheet.id; - let sheet = grid_controller.grid_mut().sheet_mut_from_id(sheet_id); for y in rect.y_range() { for x in rect.x_range() { - let cell_ref = sheet.get_or_create_cell_ref(Pos { x, y }); - cells_accessed.insert(cell_ref); + cells_accessed.insert(SheetPos { x, y, sheet_id }); } } - self.cells_accessed = cells_accessed.into_iter().collect(); + cells_accessed.iter().for_each(|sheet_pos| { + self.cells_accessed.insert(*sheet_pos); + }); Some(array) } else { // unable to find sheet by name, generate error @@ -86,7 +64,7 @@ impl TransactionInProgress { } else { "Sheet not found".to_string() }; - self.code_cell_sheet_error(grid_controller, msg, get_cells.line_number()); + self.code_cell_sheet_error(msg, get_cells.line_number()); Some(CellsForArray::new(vec![], true)) } } diff --git a/quadratic-core/src/controller/execution/mod.rs b/quadratic-core/src/controller/execution/mod.rs new file mode 100644 index 0000000000..27d1201d70 --- /dev/null +++ b/quadratic-core/src/controller/execution/mod.rs @@ -0,0 +1,61 @@ +/// This module handles the application of operations to the Grid. +pub mod compute; +pub mod control_transaction; +pub mod eval_formula; +/// +pub mod execute_operation; +pub mod get_cells; +use serde::{Deserialize, Serialize}; + +use crate::controller::{transaction_summary::TransactionSummary, GridController}; + +use super::Transaction; + +#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)] +pub enum TransactionType { + #[default] + Unset, + User, + Undo, + Redo, + Multiplayer, +} + +impl GridController { + /// Clear the `cells_to_compute` attribute + pub fn clear_cells_to_compute(&mut self) { + self.cells_to_compute.clear(); + } + + /// recalculate bounds for changed sheets + pub fn transaction_updated_bounds(&mut self) { + self.sheets_with_changed_bounds + .clone() + .iter() + .for_each(|sheet_id| { + let sheet = self.grid_mut().sheet_mut_from_id(*sheet_id); + sheet.recalculate_bounds(); + }); + } + + /// returns the TransactionSummary + pub fn prepare_transaction_summary(&mut self) -> TransactionSummary { + if self.complete { + self.summary.forward_operations = Some( + serde_json::to_string(&self.forward_operations) + .expect("Failed to serialize forward operations"), + ); + } + let summary = self.summary.clone(); + self.summary.clear(self.complete); + summary + } + + /// Creates a transaction to save to the Undo/Redo stack + fn to_transaction(&self) -> Transaction { + Transaction { + operations: self.reverse_operations.clone().into_iter().rev().collect(), + cursor: self.cursor.clone(), + } + } +} diff --git a/quadratic-core/src/controller/export.rs b/quadratic-core/src/controller/export.rs index 11f42053d7..3dd48822c2 100644 --- a/quadratic-core/src/controller/export.rs +++ b/quadratic-core/src/controller/export.rs @@ -1,16 +1,17 @@ use anyhow::Result; use csv::Writer; -use super::{auto_complete::cell_values_in_rect, GridController}; +use super::GridController; use crate::{grid::SheetId, Rect}; impl GridController { - /// exports a CSV string from a selction on the grid. + /// exports a CSV string from a selection on the grid. /// /// Returns a [`String`]. pub fn export_csv_selection(&self, sheet_id: SheetId, selection: &Rect) -> Result { let sheet = self.sheet(sheet_id); - let values = cell_values_in_rect(selection, sheet)? + let values = sheet + .cell_values_in_rect(selection)? .into_cell_values_vec() .iter() .map(|record| record.to_string()) @@ -41,7 +42,7 @@ mod tests { for y in selection.y_range() { for x in selection.x_range() { - grid_controller.set_cell_value(sheet_id, (x, y).into(), vals[count].into(), None); + grid_controller.set_cell_value((x, y, sheet_id).into(), vals[count].into(), None); count += 1; } } diff --git a/quadratic-core/src/controller/operations.rs b/quadratic-core/src/controller/operations.rs deleted file mode 100644 index 794f3c3a02..0000000000 --- a/quadratic-core/src/controller/operations.rs +++ /dev/null @@ -1,534 +0,0 @@ -use std::collections::HashSet; - -use indexmap::IndexSet; - -use crate::{grid::*, Array, CellValue, Pos}; - -use super::{ - formatting::CellFmtArray, - operation::Operation, - transaction_summary::{CellSheetsModified, TransactionSummary}, - update_code_cell_value::fetch_code_cell_difference, - GridController, -}; - -impl GridController { - /// Executes the given operation and returns the reverse operation. - /// The only way to modify the internal state of the grid is through this function, with an operation. - /// Operations must always return a reverse operation that can be used to undo the operation. - pub fn execute_operation( - &mut self, - op: Operation, - cells_updated: &mut IndexSet, - cells_to_compute: &mut IndexSet, - summary: &mut TransactionSummary, - sheets_with_changed_bounds: &mut HashSet, - compute: bool, - ) -> Vec { - let mut reverse_operations = vec![]; - match op { - Operation::SetCellValues { region, values } => { - sheets_with_changed_bounds.insert(region.sheet); - let sheet = self.grid.sheet_mut_from_id(region.sheet); - - let size = region.size().expect("msg: error getting size of region"); - let old_values = region - .iter() - .zip(values.into_cell_values_vec()) - .map(|(cell_ref, value)| { - let pos = sheet.cell_ref_to_pos(cell_ref)?; - let response = sheet.set_cell_value(pos, value)?; - if response.html { - summary.html.insert(cell_ref.sheet); - } - Some(response.old_value) - }) - .map(|old_value| old_value.unwrap_or(CellValue::Blank)) - .collect(); - cells_updated.insert(region.clone()); - - let old_values = Array::new_row_major(size, old_values) - .expect("error constructing array of old values for SetCells operation"); - - CellSheetsModified::add_region(&mut summary.cell_sheets_modified, sheet, ®ion); - - // check if override any code cells - let sheet = self.grid.sheet_from_id(region.sheet); - let code_cells_to_delete = sheet - .code_cells - .iter() - .filter_map(|(cell_ref, _)| { - if region.contains(cell_ref) { - let pos = sheet.cell_ref_to_pos(*cell_ref)?; - Some((*cell_ref, pos)) - } else { - None - } - }) - .collect::>(); - - // remove the code cells - let sheet_id = sheet.id; - for (cell_ref, pos) in code_cells_to_delete { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - let old_value = sheet.set_code_cell_value(pos, None); - fetch_code_cell_difference( - self, - sheet_id, - pos, - old_value.clone(), - None, - summary, - cells_to_compute, - &mut reverse_operations, - ); - reverse_operations.push(Operation::SetCellCode { - cell_ref, - code_cell_value: old_value, - }); - } - - // check for changes in spills - for cell_ref in region.iter() { - let sheet = self.grid.sheet_from_id(cell_ref.sheet); - if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { - // if there is a value, check if it caused a spill - if sheet.get_cell_value(pos).is_some() { - self.check_spill( - cell_ref, - cells_to_compute, - summary, - &mut reverse_operations, - ); - } else { - // otherwise check if it released a spill - self.update_code_cell_value_if_spill_error_released( - cell_ref, - cells_to_compute, - summary, - &mut reverse_operations, - ); - } - } - } - - summary.generate_thumbnail = - summary.generate_thumbnail || self.thumbnail_dirty_region(®ion); - - reverse_operations.push(Operation::SetCellValues { - region, - values: old_values, - }); - } - Operation::SetCellCode { - cell_ref, - code_cell_value, - } => { - let is_code_cell_empty = code_cell_value.is_none(); - let sheet_id = cell_ref.sheet; - - sheets_with_changed_bounds.insert(sheet_id); - - let sheet = self.grid.sheet_mut_from_id(sheet_id); - let old_spill = sheet.get_spill(cell_ref); - - // TODO(ddimaria): resolve comment from @HactarCE - // note: this is a non-trivial refactor, but a good one to make - // - // Use .cloned() later if the value needs to be cloned, not here. - // fetch_code_cell_difference() should take &Option - // or possibly Option. - let old_code_cell_value = sheet.get_code_cell_from_ref(cell_ref).cloned(); - let pos = if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { - pos - } else { - return vec![]; - }; - - // for compute, we keep the original cell output to avoid flashing of output (since values will be overridden once computation is complete) - let sheet = self.grid.sheet_mut_from_id(sheet_id); - if compute { - if let Some(code_cell_value) = code_cell_value { - let updated_code_cell_value = - if let Some(old_code_cell_value) = &old_code_cell_value { - let mut updated_code_cell_value = code_cell_value.clone(); - updated_code_cell_value.output = old_code_cell_value.output.clone(); - updated_code_cell_value - } else { - code_cell_value - }; - sheet.set_code_cell_value(pos, Some(updated_code_cell_value)); - } else { - sheet.set_code_cell_value(pos, code_cell_value); - fetch_code_cell_difference( - self, - sheet_id, - pos, - old_code_cell_value.clone(), - None, - summary, - cells_to_compute, - &mut reverse_operations, - ); - let sheet = self.grid.sheet_mut_from_id(sheet_id); - sheet.set_code_cell_value(pos, None); - } - cells_to_compute.insert(cell_ref); - } else { - // need to update summary (cells_to_compute will be ignored) - fetch_code_cell_difference( - self, - sheet_id, - pos, - old_code_cell_value.clone(), - code_cell_value.clone(), - summary, - cells_to_compute, - &mut reverse_operations, - ); - let sheet = self.grid.sheet_mut_from_id(sheet_id); - sheet.set_code_cell_value(pos, code_cell_value); - } - - // TODO(ddimaria): resolve comment from @HactarCE: - // - // Can we use SheetPos instead of CellSheetsModified? I'd like - // to avoid using String for sheet IDs as much as possible. If - // it's needed for JS interop, then let's impl Serialize and - // Deserialize on SheetId to make it serialize as a string. - summary - .cell_sheets_modified - .insert(CellSheetsModified::new(sheet_id, pos)); - summary.code_cells_modified.insert(sheet_id); - - // check if a new code_cell causes a spill error in another code cell - if old_code_cell_value.is_none() && !is_code_cell_empty { - if let Some(old_spill) = old_spill { - if old_spill != cell_ref { - self.set_spill_error( - old_spill, - cells_to_compute, - summary, - &mut reverse_operations, - ); - } - } - } - - // check if deleting a code cell releases a spill - if is_code_cell_empty { - self.update_code_cell_value_if_spill_error_released( - cell_ref, - cells_to_compute, - summary, - &mut reverse_operations, - ); - } - - reverse_operations.push(Operation::SetCellCode { - cell_ref, - code_cell_value: old_code_cell_value, - }); - } - Operation::SetCellFormats { region, attr } => { - sheets_with_changed_bounds.insert(region.sheet); - - if let CellFmtArray::FillColor(_) = attr { - summary.fill_sheets_modified.push(region.sheet); - } - - // todo: this is too slow -- perhaps call this again when we have a better way of setting multiple formats within an array - // or when we get rid of CellRefs (which I think is the reason this is slow) - // summary.generate_thumbnail = - // summary.generate_thumbnail || self.thumbnail_dirty_region(region.clone()); - - let old_attr = match attr { - CellFmtArray::Align(align) => { - CellFmtArray::Align(self.set_cell_formats_for_type::( - ®ion, - align, - Some(&mut summary.cell_sheets_modified), - )) - } - - CellFmtArray::Wrap(wrap) => { - CellFmtArray::Wrap(self.set_cell_formats_for_type::( - ®ion, - wrap, - Some(&mut summary.cell_sheets_modified), - )) - } - CellFmtArray::NumericFormat(num_fmt) => CellFmtArray::NumericFormat( - self.set_cell_formats_for_type::( - ®ion, - num_fmt, - Some(&mut summary.cell_sheets_modified), - ), - ), - CellFmtArray::NumericDecimals(num_decimals) => CellFmtArray::NumericDecimals( - self.set_cell_formats_for_type::( - ®ion, - num_decimals, - Some(&mut summary.cell_sheets_modified), - ), - ), - CellFmtArray::NumericCommas(num_commas) => CellFmtArray::NumericCommas( - self.set_cell_formats_for_type::( - ®ion, - num_commas, - Some(&mut summary.cell_sheets_modified), - ), - ), - CellFmtArray::Bold(bold) => { - CellFmtArray::Bold(self.set_cell_formats_for_type::( - ®ion, - bold, - Some(&mut summary.cell_sheets_modified), - )) - } - CellFmtArray::Italic(italic) => { - CellFmtArray::Italic(self.set_cell_formats_for_type::( - ®ion, - italic, - Some(&mut summary.cell_sheets_modified), - )) - } - CellFmtArray::TextColor(text_color) => { - CellFmtArray::TextColor(self.set_cell_formats_for_type::( - ®ion, - text_color, - Some(&mut summary.cell_sheets_modified), - )) - } - CellFmtArray::FillColor(fill_color) => { - summary.fill_sheets_modified.push(region.sheet); - CellFmtArray::FillColor( - self.set_cell_formats_for_type::(®ion, fill_color, None), - ) - } - CellFmtArray::RenderSize(output_size) => { - summary.html.insert(region.sheet); - CellFmtArray::RenderSize(self.set_cell_formats_for_type::( - ®ion, - output_size, - None, - )) - } - }; - reverse_operations.push(Operation::SetCellFormats { - region, - attr: old_attr, - }); - } - Operation::SetBorders { region, borders } => { - sheets_with_changed_bounds.insert(region.sheet); - summary.border_sheets_modified.push(region.sheet); - summary.generate_thumbnail = - summary.generate_thumbnail || self.thumbnail_dirty_region(®ion); - - let sheet = self.grid.sheet_mut_from_id(region.sheet); - - let old_borders = sheet.set_region_borders(®ion, borders); - reverse_operations.push(Operation::SetBorders { - region, - borders: old_borders, - }); - } - Operation::AddSheet { sheet } => { - // todo: need to handle the case where sheet.order overlaps another sheet order - // this may happen after (1) delete a sheet; (2) MP update w/an added sheet; and (3) undo the deleted sheet - let sheet_id = sheet.id; - self.grid - .add_sheet(Some(sheet)) - .expect("duplicate sheet name"); - summary.sheet_list_modified = true; - summary.html.insert(sheet_id); - - reverse_operations.push(Operation::DeleteSheet { sheet_id }); - } - Operation::DeleteSheet { sheet_id } => { - let deleted_sheet = self.grid.remove_sheet(sheet_id); - summary.sheet_list_modified = true; - - reverse_operations.push(Operation::AddSheet { - sheet: deleted_sheet, - }); - } - Operation::ReorderSheet { target, order } => { - let old_first = self.grid.first_sheet_id(); - let sheet = self.grid.sheet_from_id(target); - let original_order = sheet.order.clone(); - self.grid.move_sheet(target, order); - summary.sheet_list_modified = true; - - if old_first != self.grid.first_sheet_id() { - summary.generate_thumbnail = true; - } - - reverse_operations.push(Operation::ReorderSheet { - target, - order: original_order, - }); - } - Operation::SetSheetName { sheet_id, name } => { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - let old_name = sheet.name.clone(); - sheet.name = name; - summary.sheet_list_modified = true; - - reverse_operations.push(Operation::SetSheetName { - sheet_id, - name: old_name, - }); - } - Operation::SetSheetColor { sheet_id, color } => { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - let old_color = sheet.color.clone(); - sheet.color = color; - summary.sheet_list_modified = true; - - reverse_operations.push(Operation::SetSheetColor { - sheet_id, - color: old_color, - }); - } - - Operation::ResizeColumn { - sheet_id, - column, - new_size, - } => { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - if let Some(x) = sheet.get_column_index(column) { - summary.offsets_modified.push(sheet.id); - let old_size = sheet.offsets.set_column_width(x, new_size); - summary.generate_thumbnail = summary.generate_thumbnail - || self.thumbnail_dirty_pos(sheet_id, Pos { x, y: 0 }); - - reverse_operations.push(Operation::ResizeColumn { - sheet_id, - column, - new_size: old_size, - }); - } - } - - Operation::ResizeRow { - sheet_id, - row, - new_size, - } => { - let sheet = self.grid.sheet_mut_from_id(sheet_id); - if let Some(y) = sheet.get_row_index(row) { - let old_size = sheet.offsets.set_row_height(y, new_size); - summary.offsets_modified.push(sheet.id); - summary.generate_thumbnail = summary.generate_thumbnail - || self.thumbnail_dirty_pos(sheet_id, Pos { x: 0, y }); - - reverse_operations.push(Operation::ResizeRow { - sheet_id, - row, - new_size: old_size, - }); - } - } - }; - reverse_operations - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn execute(gc: &mut GridController, operation: Operation) { - let mut cells_updated = IndexSet::new(); - let mut cells_to_compute = IndexSet::new(); - let mut summary = TransactionSummary::default(); - let mut sheets_with_changed_bounds = HashSet::new(); - gc.execute_operation( - operation, - &mut cells_updated, - &mut cells_to_compute, - &mut summary, - &mut sheets_with_changed_bounds, - false, - ); - } - - #[test] - fn test_execute_operation_set_sheet_color() { - let mut gc = GridController::new(); - let sheet_id = gc.sheet_ids()[0]; - let color = Some("red".to_string()); - let operation = Operation::SetSheetColor { - sheet_id, - color: color.clone(), - }; - - assert_eq!( - format!("{:?}", operation), - format!( - "SetSheetColor {{ sheet_id: SheetId {{ id: {} }}, color: Some(\"red\") }}", - sheet_id - ) - ); - - execute(&mut gc, operation); - assert_eq!(gc.grid.sheets()[0].color, color); - } - - #[test] - fn test_execute_operation_resize_column() { - let mut gc = GridController::new(); - let sheet = &mut gc.grid_mut().sheets_mut()[0]; - let (_, column) = sheet.get_or_create_column(0); - let column_id = column.id; - let sheet_id = sheet.id; - let new_size = 100.0; - let operation = Operation::ResizeColumn { - sheet_id, - column: column_id, - new_size, - }; - - assert_eq!( - format!("{:?}", operation), - format!( - "ResizeColumn {{ sheet_id: SheetId {{ id: {} }}, column: ColumnId {{ id: {} }}, new_size: {:.1} }}", - sheet_id, column_id, new_size - ) - ); - - execute(&mut gc, operation); - let column_width = gc.grid.sheets()[0].offsets.column_width(0); - assert_eq!(column_width, new_size); - } - - #[test] - fn test_execute_operation_resize_row() { - let mut gc = GridController::new(); - let sheet = &mut gc.grid_mut().sheets_mut()[0]; - let row = sheet.get_or_create_row(0); - let row_id = row.id; - let sheet_id = sheet.id; - let new_size = 100.0; - let operation = Operation::ResizeRow { - sheet_id, - row: row_id, - new_size, - }; - - assert_eq!( - format!("{:?}", operation), - format!( - "ResizeRow {{ sheet_id: SheetId {{ id: {} }}, row: RowId {{ id: {} }}, new_size: {:.1} }}", - sheet_id, row_id, new_size - ) - ); - - execute(&mut gc, operation); - let row_height = gc.grid.sheets()[0].offsets.row_height(0); - assert_eq!(row_height, new_size); - } -} diff --git a/quadratic-core/src/controller/operations/autocomplete.rs b/quadratic-core/src/controller/operations/autocomplete.rs new file mode 100644 index 0000000000..3e59c79150 --- /dev/null +++ b/quadratic-core/src/controller/operations/autocomplete.rs @@ -0,0 +1,649 @@ +use anyhow::{anyhow, Result}; +use itertools::Itertools; + +use crate::{ + controller::GridController, + grid::{ + formatting::CellFmtArray, + series::{find_auto_complete, SeriesOptions}, + SheetId, + }, + util::maybe_reverse_range, + Array, CellValue, Pos, Rect, SheetRect, +}; + +use super::operation::Operation; + +#[derive(PartialEq)] +pub enum ExpandDirection { + Up, + Down, + Left, + Right, +} + +impl GridController { + /// Extend and/or shrink the contents of selection to range by inferring patterns. + /// + /// selection: the range of cells to be expanded + /// + /// range: the range of cells to expand to + /// + /// cursor: the cursor position for the undo/redo stack + pub fn autocomplete_operations( + &mut self, + sheet_id: SheetId, + selection: Rect, + range: Rect, + ) -> Result> { + let mut selection = selection; + let mut operations = vec![]; + let mut initial_down_range: Option = None; + let mut initial_up_range: Option = None; + + let should_expand_up = range.min.y < selection.min.y; + let should_expand_down = range.max.y > selection.max.y; + let should_expand_left = range.min.x < selection.min.x; + let should_expand_right = range.max.x > selection.max.x; + + let should_shrink_width = range.max.x < selection.max.x; + let should_shrink_height = range.max.y < selection.max.y; + + // shrink width, from right to left + if should_shrink_width { + let delete_range = SheetRect::new_pos_span( + (range.max.x + 1, range.min.y).into(), + (selection.max.x, selection.max.y).into(), + sheet_id, + ); + let ops = self.shrink(delete_range); + operations.extend(ops); + selection.max.x = range.max.x; + } + + // shrink height, from bottom to top + if should_shrink_height { + let delete_range = SheetRect::new_pos_span( + (selection.min.x, range.max.y + 1).into(), + (range.max.x, selection.max.y).into(), + sheet_id, + ); + let ops = self.shrink(delete_range); + operations.extend(ops); + selection.max.y = range.max.y; + } + + // expand up + if should_expand_up { + let new_range = Rect::new_span( + (selection.min.x, selection.min.y - 1).into(), + (selection.max.x, range.min.y).into(), + ); + let ops = self.expand_up(sheet_id, &selection, &new_range)?; + operations.extend(ops); + initial_up_range = Some(range); + } + + // expand down + if should_expand_down { + let new_range = Rect::new_span( + (selection.min.x, selection.max.y + 1).into(), + (selection.max.x, range.max.y).into(), + ); + let ops = self.expand_down(sheet_id, &selection, &new_range)?; + operations.extend(ops); + initial_down_range = Some(range); + } + // expand left + if should_expand_left { + let new_range = Rect::new_span( + (range.min.x, selection.min.y).into(), + (selection.min.x - 1, selection.max.y).into(), + ); + + let down_range = initial_down_range.map(|initial_down_range| { + Rect::new_span( + (initial_down_range.min.x, selection.max.y + 1).into(), + (selection.min.x - 1, initial_down_range.max.y).into(), + ) + }); + + let up_range = initial_up_range.map(|initial_up_range| { + Rect::new_span( + initial_up_range.min, + (selection.min.x - 1, selection.min.y - 1).into(), + ) + }); + + let ops = self.expand_left(sheet_id, &selection, &new_range, down_range, up_range)?; + operations.extend(ops); + } + + // expand right + if should_expand_right { + let new_range = Rect::new_span( + (selection.max.x + 1, selection.max.y).into(), + (range.max.x, selection.max.y).into(), + ); + + let down_range = initial_down_range.map(|initial_down_range| { + Rect::new_span( + (selection.max.x + 1, selection.max.y + 1).into(), + initial_down_range.max, + ) + }); + + let up_range = initial_up_range.map(|initial_up_range| { + Rect::new_span( + (selection.max.x + 1, initial_up_range.min.y).into(), + (initial_up_range.max.x, selection.min.y - 1).into(), + ) + }); + + let ops = self.expand_right(sheet_id, &selection, &new_range, down_range, up_range)?; + operations.extend(ops); + } + Ok(operations) + } + + /// Delete cell values and formats in a given range. + fn shrink(&mut self, delete_range: SheetRect) -> Vec { + let mut ops = vec![]; + + ops.extend(self.delete_cells_rect_operations(delete_range)); + ops.extend(self.clear_formatting_operations(delete_range)); + ops + } + + fn expand_right( + &mut self, + sheet_id: SheetId, + selection: &Rect, + range: &Rect, + down_range: Option, + up_range: Option, + ) -> Result> { + let mut format_ops = vec![]; + let mut values = vec![]; + let mut formats = vec![]; + let mut ops = selection + .y_range() + .map(|y| { + let source_row = SheetRect::new_pos_span( + (selection.min.x, y).into(), + (selection.max.x, y).into(), + sheet_id, + ); + let target_row = Rect::new_span((range.min.x, y).into(), (range.max.x, y).into()); + let format = self.get_all_cell_formats(source_row); + let width = selection.width() as usize; + + // for each column, apply the formats to a block (selection.width, y) of new cells + range.x_range().step_by(width).for_each(|x| { + let new_x = range.max.x.min(x + width as i64 - 1); + let format_rect = + SheetRect::new_pos_span((x, y).into(), (new_x, y).into(), sheet_id); + format_ops.extend(apply_formats(format_rect, &format)); + }); + + formats.push(format); + let (operations, cell_values) = self.apply_auto_complete( + sheet_id, + false, + &source_row.into(), + &target_row, + None, + )?; + values.extend(cell_values); + + Ok(operations) + }) + .flatten_ok() + .collect::>>()?; + + if let Some(down_range) = down_range { + ops.extend(self.expand_up_or_down_from_right( + sheet_id, + selection, + &down_range, + &values, + range.width() as i64, + ExpandDirection::Down, + )?); + } + + if let Some(up_range) = up_range { + ops.extend(self.expand_up_or_down_from_right( + sheet_id, + selection, + &up_range, + &values, + range.width() as i64, + ExpandDirection::Up, + )?); + } + + ops.extend(format_ops); + Ok(ops) + } + + fn expand_left( + &mut self, + sheet_id: SheetId, + selection: &Rect, + range: &Rect, + down_range: Option, + up_range: Option, + ) -> Result> { + let mut format_ops = vec![]; + let mut values = vec![]; + let mut formats = vec![]; + let mut ops = selection + .y_range() + .map(|y| { + let source_row = SheetRect::new_pos_span( + (selection.min.x, y).into(), + (selection.max.x, y).into(), + sheet_id, + ); + let target_row = Rect::new_span((range.min.x, y).into(), (range.max.x, y).into()); + let mut format = self.get_all_cell_formats(source_row); + let width = selection.width() as usize; + + // for each column, apply the formats to a block (selection.width, y) of new cells + range.x_range().rev().step_by(width).for_each(|x| { + let mut new_x = x - width as i64 + 1; + + if new_x < range.min.x { + let source_col = SheetRect::new_pos_span( + (selection.min.x + range.min.x - new_x, y).into(), + (selection.max.x, y).into(), + sheet_id, + ); + new_x = range.min.x; + format = self.get_all_cell_formats(source_col); + } + + let format_rect = + SheetRect::new_pos_span((x, y).into(), (new_x, y).into(), sheet_id); + format_ops.extend(apply_formats(format_rect, &format)); + }); + + formats.extend(format); + let (operations, cell_values) = self.apply_auto_complete( + sheet_id, + true, + &source_row.into(), + &target_row, + None, + )?; + values.extend(cell_values); + + Ok(operations) + }) + .flatten_ok() + .collect::>>()?; + + if let Some(down_range) = down_range { + ops.extend(self.expand_up_or_down_from_left( + sheet_id, + selection, + &down_range, + &values, + range.width() as i64, + ExpandDirection::Down, + )?); + } + + if let Some(up_range) = up_range { + ops.extend(self.expand_up_or_down_from_left( + sheet_id, + selection, + &up_range, + &values, + range.width() as i64, + ExpandDirection::Up, + )?); + } + + ops.extend(format_ops); + Ok(ops) + } + + fn expand_down( + &mut self, + sheet_id: SheetId, + selection: &Rect, + range: &Rect, + ) -> Result> { + let mut format_ops = vec![]; + let mut values = vec![]; + let mut formats = vec![]; + let mut ops = selection + .x_range() + .rev() + .map(|x| { + let source_col = SheetRect::new_pos_span( + (x, selection.min.y).into(), + (x, selection.max.y).into(), + sheet_id, + ); + let target_col = + Rect::new_span((x, selection.max.y + 1).into(), (x, range.max.y).into()); + let format = self.get_all_cell_formats(source_col); + let height = selection.height() as usize; + + // for each row, apply the formats to a block (x, selection.height) of new cells + range.y_range().step_by(height).for_each(|y| { + let new_y = range.max.y.min(y + height as i64 - 1); + let format_rect = + SheetRect::new_pos_span((x, y).into(), (x, new_y).into(), sheet_id); + format_ops.extend(apply_formats(format_rect, &format)); + }); + + formats.extend(format); + let (operations, cell_values) = self.apply_auto_complete( + sheet_id, + false, + &source_col.into(), + &target_col, + None, + )?; + values.extend(cell_values); + + Ok(operations) + }) + .flatten_ok() + .collect::>>()?; + + ops.extend(format_ops); + Ok(ops) + } + + fn expand_up( + &mut self, + sheet_id: SheetId, + selection: &Rect, + range: &Rect, + ) -> Result> { + let mut format_ops = vec![]; + let mut values = vec![]; + let mut formats = vec![]; + let mut ops = selection + .x_range() + .map(|x| { + let source_col = SheetRect::new_pos_span( + (x, selection.min.y).into(), + (x, selection.max.y).into(), + sheet_id, + ); + let target_col = + Rect::new_span((x, selection.min.y - 1).into(), (x, range.min.y).into()); + let mut format = self.get_all_cell_formats(source_col); + let height = selection.height() as usize; + + // for each row, apply the formats to a block (x, selection.height) of new cells + range.y_range().rev().step_by(height).for_each(|y| { + let mut new_y = y - height as i64 + 1; + + // since the new_y is less than the range min, we need to + // adjust the format since this is ine reverse order + if new_y < range.min.y { + let source_col = SheetRect::new_pos_span( + (x, selection.min.y + range.min.y - new_y).into(), + (x, selection.max.y).into(), + sheet_id, + ); + new_y = range.min.y; + format = self.get_all_cell_formats(source_col); + } + + let format_rect = + SheetRect::new_pos_span((x, y).into(), (x, new_y).into(), sheet_id); + format_ops.extend(apply_formats(format_rect, &format)); + }); + + formats.extend(format); + let (operations, cell_values) = self.apply_auto_complete( + sheet_id, + true, + &source_col.into(), + &target_col, + None, + )?; + values.extend(cell_values); + + Ok(operations) + }) + .flatten_ok() + .collect::>>()?; + + ops.extend(format_ops); + Ok(ops) + } + + fn expand_up_or_down_from_right( + &mut self, + sheet_id: SheetId, + selection: &Rect, + range: &Rect, + values: &Vec, + width: i64, + direction: ExpandDirection, + ) -> Result> { + let mut format_ops = vec![]; + let height = values.len() as i64 / width; + + let mut ops = range + .x_range() + .enumerate() + .map(|(index, x)| { + let target_col = Rect::new_span((x, range.min.y).into(), (x, range.max.y).into()); + + let vals = (0..height) + .map(|i| { + let array_index = (index as i64 + (i * width)) as usize; + values + .get(array_index) + .unwrap_or(&CellValue::Blank) + .to_owned() + }) + .collect::>(); + + let format_x = selection.min.x + (x - selection.min.x) % selection.width() as i64; + let format_source_rect = SheetRect::new_pos_span( + (format_x, selection.min.y).into(), + (format_x, selection.max.y).into(), + sheet_id, + ); + let mut format = self.get_all_cell_formats(format_source_rect); + + maybe_reverse_range(range.y_range(), direction == ExpandDirection::Up) + .step_by(height as usize) + .for_each(|y| { + let new_y = if direction == ExpandDirection::Down { + range.max.y.min(y + height - 1) + } else { + // since the new_y is less than the range min, we need to + // adjust the format since this is ine reverse order + let calc_y = y - height + 1; + if calc_y < range.min.y { + let format_source_rect = SheetRect::new_pos_span( + (format_x, selection.min.y + range.min.y - calc_y).into(), + (format_x, selection.max.y).into(), + sheet_id, + ); + format = self.get_all_cell_formats(format_source_rect); + range.min.y + } else { + y - height + 1 + } + }; + let format_rect = + SheetRect::new_pos_span((x, y).into(), (x, new_y).into(), sheet_id); + format_ops.extend(apply_formats(format_rect, &format)); + }); + + let (operations, _) = self.apply_auto_complete( + sheet_id, + direction == ExpandDirection::Up, + &target_col, + &target_col, + Some(vals), + )?; + + Ok(operations) + }) + .flatten_ok() + .collect::>>()?; + + ops.extend(format_ops); + + Ok(ops) + } + + fn expand_up_or_down_from_left( + &mut self, + sheet_id: SheetId, + selection: &Rect, + range: &Rect, + values: &Vec, + width: i64, + direction: ExpandDirection, + ) -> Result> { + let mut format_ops = vec![]; + let height = values.len() as i64 / width; + + let mut ops = range + .x_range() + .rev() + .enumerate() + .map(|(index, x)| { + let target_col = if direction == ExpandDirection::Down { + Rect::new_span((x, range.min.y).into(), (x, range.max.y).into()) + } else { + Rect::new_span((x, selection.min.y - 1).into(), (x, range.min.y).into()) + }; + + let vals = (0..height) + .map(|i| { + let array_index = (i * width) + width - index as i64 - 1; + values + .get(array_index as usize) + .unwrap_or(&CellValue::Blank) + .to_owned() + }) + .collect::>(); + + let format_x = selection.max.x - (index as i64 % selection.width() as i64); + let format_source_rect = SheetRect::new_pos_span( + (format_x, selection.min.y).into(), + (format_x, selection.max.y).into(), + sheet_id, + ); + let mut format = self.get_all_cell_formats(format_source_rect); + + maybe_reverse_range(range.y_range(), direction == ExpandDirection::Up) + .step_by(height as usize) + .for_each(|y| { + let new_y = if direction == ExpandDirection::Down { + range.max.y.min(y + height - 1) + } else { + // since the new_y is less than the range min, we need to + // adjust the format since this is ine reverse order + let calc_y = y - height + 1; + if calc_y < range.min.y { + let format_source_rect = SheetRect::new_pos_span( + (format_x, selection.min.y + range.min.y - calc_y).into(), + (format_x, selection.max.y).into(), + sheet_id, + ); + format = self.get_all_cell_formats(format_source_rect); + range.min.y + } else { + y - height + 1 + } + }; + + let format_rect = + SheetRect::new_pos_span((x, y).into(), (x, new_y).into(), sheet_id); + format_ops.extend(apply_formats(format_rect, &format)); + }); + + let (operations, _) = self.apply_auto_complete( + sheet_id, + direction == ExpandDirection::Up, + &target_col, + &target_col, + Some(vals), + )?; + + Ok(operations) + }) + .flatten_ok() + .collect::>>()?; + + ops.extend(format_ops); + + Ok(ops) + } + + /// Gven an array of values, determine if a series exists and if so, apply it. + fn apply_auto_complete( + &mut self, + sheet_id: SheetId, + negative: bool, + selection: &Rect, + range: &Rect, + cell_values: Option>, + ) -> Result<(Vec, Vec)> { + let sheet = self.sheet(sheet_id); + let values = if let Some(cell_values) = cell_values { + cell_values + } else { + sheet + .cell_values_in_rect(selection)? + .into_cell_values_vec() + .into_iter() + .collect::>() + }; + + let series = find_auto_complete(SeriesOptions { + series: values, + spaces: (range.width() * range.height()) as i32, + negative, + }); + + let values = Array::new_row_major(range.size(), series.to_owned().into()) + .map_err(|e| anyhow!("Could not create array of size {:?}: {:?}", range.size(), e))?; + + let start_pos = range.min; + let end_pos = Pos { + x: start_pos.x + values.width() as i64 - 1, + y: start_pos.y + values.height() as i64 - 1, + }; + let sheet_rect = SheetRect { + min: start_pos, + max: end_pos, + sheet_id, + }; + let ops = vec![Operation::SetCellValues { sheet_rect, values }]; + + Ok((ops, series)) + } +} + +/// Apply formats to a given region. +/// +/// TODO(ddimaria): this funcion is sufficiently generic that it could be moved +/// TODO(ddimaria): we could remove the clones below by modifying the Operation +/// calls to accept references since they don't mutate the region. +pub fn apply_formats(sheet_rect: SheetRect, formats: &[CellFmtArray]) -> Vec { + formats + .iter() + .map(|format| Operation::SetCellFormats { + sheet_rect, + attr: format.clone(), + }) + .collect() +} diff --git a/quadratic-core/src/controller/operations/borders.rs b/quadratic-core/src/controller/operations/borders.rs new file mode 100644 index 0000000000..8c12da22da --- /dev/null +++ b/quadratic-core/src/controller/operations/borders.rs @@ -0,0 +1,23 @@ +use crate::{ + controller::GridController, + grid::{generate_borders, BorderSelection, BorderStyle}, + SheetRect, +}; + +use super::operation::Operation; + +impl GridController { + pub fn set_borders_operations( + &mut self, + sheet_rect: SheetRect, + selections: Vec, + style: Option, + ) -> Vec { + let sheet = self.sheet(sheet_rect.sheet_id); + let borders = generate_borders(sheet, &sheet_rect.into(), selections, style); + vec![Operation::SetBorders { + sheet_rect, + borders, + }] + } +} diff --git a/quadratic-core/src/controller/operations/cell_value.rs b/quadratic-core/src/controller/operations/cell_value.rs new file mode 100644 index 0000000000..8e8d8f3c97 --- /dev/null +++ b/quadratic-core/src/controller/operations/cell_value.rs @@ -0,0 +1,118 @@ +use std::str::FromStr; + +use bigdecimal::BigDecimal; + +use crate::{ + controller::GridController, + grid::{formatting::CellFmtArray, NumericDecimals, NumericFormat, NumericFormatKind}, + Array, CellValue, RunLengthEncoding, SheetPos, SheetRect, +}; + +use super::operation::Operation; + +impl GridController { + pub fn string_to_cell_value( + &mut self, + sheet_pos: SheetPos, + value: &str, + ) -> (Vec, CellValue) { + let mut ops = vec![]; + let sheet_rect: SheetRect = sheet_pos.into(); + let cell_value = if value.is_empty() { + CellValue::Blank + } else if let Some((currency, number)) = CellValue::unpack_currency(value) { + let numeric_format = NumericFormat { + kind: NumericFormatKind::Currency, + symbol: Some(currency), + }; + ops.push(Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( + Some(numeric_format), + 1, + )), + }); + // only change decimal places if decimals have not been set + let sheet = self.grid.sheet_from_id(sheet_pos.sheet_id); + if sheet + .get_formatting_value::(sheet_pos.into()) + .is_none() + { + ops.push(Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat(Some(2), 1)), + }); + } + CellValue::Number(number) + } else if let Ok(bd) = BigDecimal::from_str(value) { + CellValue::Number(bd) + } else if let Some(percent) = CellValue::unpack_percentage(value) { + let numeric_format = NumericFormat { + kind: NumericFormatKind::Percentage, + symbol: None, + }; + ops.push(Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( + Some(numeric_format), + 1, + )), + }); + CellValue::Number(percent) + } else { + CellValue::Text(value.into()) + }; + (ops, cell_value) + } + + pub fn set_cell_value_operations( + &mut self, + sheet_pos: SheetPos, + value: String, + ) -> Vec { + let mut ops = vec![]; + + // strip whitespace + let value = value.trim(); + + // convert the string to a cell value and generate necessary operations + let (operations, cell_value) = self.string_to_cell_value(sheet_pos, value); + ops.extend(operations); + + ops.push(Operation::SetCellValues { + sheet_rect: sheet_pos.into(), + values: Array::from(cell_value), + }); + ops + } + + /// Generates and returns the set of operations to deleted the values and code in a given region + /// Does not commit the operations or create a transaction. + pub fn delete_cells_rect_operations(&mut self, sheet_rect: SheetRect) -> Vec { + let mut ops = vec![]; + let values = Array::new_empty(sheet_rect.size()); + ops.push(Operation::SetCellValues { sheet_rect, values }); + + let sheet = self.grid.sheet_from_id(sheet_rect.sheet_id); + + // collect all the code cells in the region + for pos in sheet.code_cells.keys() { + if sheet_rect.contains(pos.to_sheet_pos(sheet_rect.sheet_id)) { + ops.push(Operation::SetCellCode { + sheet_pos: pos.to_sheet_pos(sheet_rect.sheet_id), + code_cell_value: None, + }); + } + } + ops + } + + pub fn delete_values_and_formatting_operations( + &mut self, + sheet_rect: SheetRect, + ) -> Vec { + let mut ops = self.delete_cells_rect_operations(sheet_rect); + ops.extend(self.clear_formatting_operations(sheet_rect)); + ops + } +} diff --git a/quadratic-core/src/controller/operations/clipboard.rs b/quadratic-core/src/controller/operations/clipboard.rs new file mode 100644 index 0000000000..51d473f417 --- /dev/null +++ b/quadratic-core/src/controller/operations/clipboard.rs @@ -0,0 +1,256 @@ +use super::operation::Operation; +use crate::{ + controller::GridController, + grid::{ + formatting::CellFmtArray, generate_borders_full, BorderSelection, CellBorders, + CodeCellValue, + }, + Array, ArraySize, CellValue, Pos, SheetPos, SheetRect, +}; +use anyhow::{Error, Result}; +use regex::Regex; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct ClipboardCell { + pub value: Option, + pub spill: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Clipboard { + pub w: u32, + pub h: u32, + pub cells: Vec, + pub formats: Vec, + pub borders: Vec<(i64, i64, Option)>, + pub code: Vec<(Pos, CodeCellValue)>, +} + +impl GridController { + pub fn cut_to_clipboard_operations( + &mut self, + sheet_rect: SheetRect, + ) -> (Vec, String, String) { + let copy = self.copy_to_clipboard(sheet_rect); + let operations = self.delete_values_and_formatting_operations(sheet_rect); + (operations, copy.0, copy.1) + } + + fn array_from_clipboard_cells(clipboard: Clipboard) -> Option { + if clipboard.w == 0 && clipboard.h == 0 { + return None; + } + + let mut array = Array::new_empty(ArraySize::new(clipboard.w, clipboard.h).unwrap()); + let mut x = 0; + let mut y = 0; + + clipboard.cells.iter().for_each(|cell| { + let value = cell.value.to_owned().map_or(CellValue::Blank, |v| v); + // ignore result errors + let _ = array.set(x, y, value); + + x += 1; + + if x == clipboard.w { + x = 0; + y += 1; + } + }); + + Some(array) + } + + fn set_clipboard_cells(&mut self, start_pos: SheetPos, clipboard: Clipboard) -> Vec { + let mut compute = false; + let sheet_rect = SheetRect { + min: start_pos.into(), + max: Pos { + x: start_pos.x + (clipboard.w as i64) - 1, + y: start_pos.y + (clipboard.h as i64) - 1, + }, + sheet_id: start_pos.sheet_id, + }; + let formats = clipboard.formats.clone(); + let borders = clipboard.borders.clone(); + let code = clipboard.code.clone(); + + let mut ops = vec![]; + let values = GridController::array_from_clipboard_cells(clipboard); + if let Some(values) = values { + ops.push(Operation::SetCellValues { sheet_rect, values }); + compute = true; + } + + let sheet = self.grid.sheet_mut_from_id(start_pos.sheet_id); + + // remove any overlapping code cells (which will automatically set the reverse operations) + for x in sheet_rect.x_range() { + for y in sheet_rect.y_range() { + let pos = Pos { x, y }; + if let Some(_code_cell) = sheet.get_code_cell(pos) { + // no need to clear code cells that are being pasted + if !code.iter().any(|(code_pos, _)| { + Pos { + x: code_pos.x + start_pos.x, + y: code_pos.y + start_pos.y, + } == pos + }) { + ops.push(Operation::SetCellCode { + sheet_pos: pos.to_sheet_pos(start_pos.sheet_id), + code_cell_value: None, + }); + compute = true; + } + } + } + } + + // add copied code cells to the sheet + code.iter().for_each(|entry| { + let sheet_pos = SheetPos { + x: entry.0.x + start_pos.x, + y: entry.0.y + start_pos.y, + sheet_id: start_pos.sheet_id, + }; + ops.push(Operation::SetCellCode { + sheet_pos, + code_cell_value: Some(entry.1.clone()), + }); + compute = true; + }); + + formats.iter().for_each(|format| { + ops.push(Operation::SetCellFormats { + sheet_rect, + attr: format.clone(), + }); + }); + + // add borders to the sheet + borders.iter().for_each(|(x, y, cell_borders)| { + if let Some(cell_borders) = cell_borders { + let mut border_selections = vec![]; + let mut border_styles = vec![]; + let sheet_rect: SheetRect = SheetPos { + sheet_id: sheet.id, + x: *x + start_pos.x, + y: *y + start_pos.y, + } + .into(); + + cell_borders + .borders + .iter() + .enumerate() + .for_each(|(index, border_style)| { + if let Some(border_style) = border_style.to_owned() { + let border_selection = match index { + 0 => BorderSelection::Left, + 1 => BorderSelection::Top, + 2 => BorderSelection::Right, + 3 => BorderSelection::Bottom, + _ => BorderSelection::Clear, + }; + border_selections.push(border_selection); + border_styles.push(Some(border_style)); + } + }); + + let borders = generate_borders_full( + sheet, + &sheet_rect.into(), + border_selections, + border_styles, + ); + ops.push(Operation::SetBorders { + sheet_rect, + borders, + }); + } + }); + ops + } + + pub fn paste_plain_text_operations( + &mut self, + start_pos: SheetPos, + clipboard: String, + ) -> Vec { + let lines: Vec<&str> = clipboard.split('\n').collect(); + + let mut ops = vec![]; + + let cell_values = lines + .iter() + .enumerate() + .map(|(x, line)| { + line.split('\t') + .enumerate() + .map(|(y, value)| { + let (operations, cell_value) = self.string_to_cell_value( + SheetPos { + x: start_pos.x + x as i64, + y: start_pos.y + y as i64, + sheet_id: start_pos.sheet_id, + }, + value, + ); + ops.extend(operations); + cell_value + }) + .collect::>() + }) + .collect::>>(); + + let array = Array::from(cell_values); + let sheet_rect = SheetRect::new_pos_span( + start_pos.into(), + ( + start_pos.x + array.width() as i64 - 1, + start_pos.y + array.height() as i64 - 1, + ) + .into(), + start_pos.sheet_id, + ); + ops.push(Operation::SetCellValues { + sheet_rect, + values: array, + }); + + ops + } + + // todo: parse table structure to provide better pasting experience from other spreadsheets + pub fn paste_html_operations( + &mut self, + sheet_pos: SheetPos, + html: String, + ) -> Result> { + // use regex to find data-quadratic + match Regex::new(r#"data-quadratic="(.*)"> Err(Error::msg("Regex creation error")), + Ok(re) => { + let Some(data) = re.captures(&html) else { + return Err(Error::msg("Regex capture error")); + }; + let result = &data.get(1).map_or("", |m| m.as_str()); + + // decode html in attribute + let unencoded = htmlescape::decode_html(result); + if unencoded.is_err() { + return Err(Error::msg("Html decode error")); + } + + // parse into Clipboard + let parsed = serde_json::from_str::(&unencoded.unwrap()); + if parsed.is_err() { + return Err(Error::msg("Clipboard parse error")); + } + let clipboard = parsed.unwrap(); + Ok(self.set_clipboard_cells(sheet_pos, clipboard)) + } + } + } +} diff --git a/quadratic-core/src/controller/operations/code_cell.rs b/quadratic-core/src/controller/operations/code_cell.rs new file mode 100644 index 0000000000..11f5f89e50 --- /dev/null +++ b/quadratic-core/src/controller/operations/code_cell.rs @@ -0,0 +1,41 @@ +use crate::{ + controller::GridController, + grid::{CodeCellLanguage, CodeCellValue}, + util::date_string, + Array, CellValue, SheetPos, SheetRect, +}; + +use super::operation::Operation; + +impl GridController { + pub fn set_cell_code_operations( + &mut self, + sheet_pos: SheetPos, + language: CodeCellLanguage, + code_string: String, + ) -> Vec { + let sheet = self.grid.sheet_mut_from_id(sheet_pos.sheet_id); + let mut ops = vec![]; + + // remove any values that were originally over the code cell + if sheet.get_cell_value_only(sheet_pos.into()).is_some() { + ops.push(Operation::SetCellValues { + sheet_rect: SheetRect::from(sheet_pos), + values: Array::from(CellValue::Blank), + }); + } + + ops.push(Operation::SetCellCode { + sheet_pos, + code_cell_value: Some(CodeCellValue { + language, + code_string, + formatted_code_string: None, + output: None, + last_modified: date_string(), + }), + }); + + ops + } +} diff --git a/quadratic-core/src/controller/operations/formatting.rs b/quadratic-core/src/controller/operations/formatting.rs new file mode 100644 index 0000000000..9167d0d906 --- /dev/null +++ b/quadratic-core/src/controller/operations/formatting.rs @@ -0,0 +1,168 @@ +use crate::{ + controller::GridController, + grid::{ + formatting::CellFmtArray, generate_borders, BorderSelection, NumericCommas, NumericFormat, + NumericFormatKind, + }, + RunLengthEncoding, SheetPos, SheetRect, +}; + +use super::operation::Operation; + +impl GridController { + pub fn set_currency_operations( + &mut self, + sheet_rect: &SheetRect, + symbol: Option, + ) -> Vec { + vec![ + Operation::SetCellFormats { + sheet_rect: *sheet_rect, + attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( + Some(NumericFormat { + kind: NumericFormatKind::Currency, + symbol, + }), + sheet_rect.len(), + )), + }, + // todo: this should not set the decimals + // default for currency should be 2 but we should not actually change it + Operation::SetCellFormats { + sheet_rect: *sheet_rect, + attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat( + Some(2), + sheet_rect.len(), + )), + }, + ] + } + + /// Sets NumericFormat and NumericDecimals to None + pub fn remove_number_formatting_operations( + &mut self, + sheet_rect: &SheetRect, + ) -> Vec { + vec![ + Operation::SetCellFormats { + sheet_rect: *sheet_rect, + attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( + None, + sheet_rect.len(), + )), + }, + Operation::SetCellFormats { + sheet_rect: *sheet_rect, + attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat( + None, + sheet_rect.len(), + )), + }, + Operation::SetCellFormats { + sheet_rect: *sheet_rect, + attr: CellFmtArray::NumericCommas(RunLengthEncoding::repeat( + None, + sheet_rect.len(), + )), + }, + ] + } + + pub fn change_decimal_places_operations( + &mut self, + source: SheetPos, + sheet_rect: SheetRect, + delta: isize, + ) -> Vec { + let sheet = self.sheet(source.sheet_id); + let is_percentage = + sheet.cell_numeric_format_kind(source.into()) == Some(NumericFormatKind::Percentage); + let decimals = sheet + .decimal_places(source.into(), is_percentage) + .unwrap_or(0); + if decimals + (delta as i16) < 0 { + return vec![]; + } + let numeric_decimals = Some(decimals + delta as i16); + vec![Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat( + numeric_decimals, + sheet_rect.len(), + )), + }] + } + + pub fn toggle_commas_operations( + &mut self, + source: SheetPos, + sheet_rect: SheetRect, + ) -> Vec { + let sheet = self.sheet(source.sheet_id); + let commas = + if let Some(commas) = sheet.get_formatting_value::(source.into()) { + !commas + } else { + true + }; + vec![Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::NumericCommas(RunLengthEncoding::repeat( + Some(commas), + sheet_rect.len(), + )), + }] + } + + pub fn clear_formatting_operations(&mut self, sheet_rect: SheetRect) -> Vec { + let len = sheet_rect.size().len(); + let mut ops = vec![ + Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::Align(RunLengthEncoding::repeat(None, len)), + }, + Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::Wrap(RunLengthEncoding::repeat(None, len)), + }, + Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat(None, len)), + }, + Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat(None, len)), + }, + Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::Bold(RunLengthEncoding::repeat(None, len)), + }, + Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::Italic(RunLengthEncoding::repeat(None, len)), + }, + Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::TextColor(RunLengthEncoding::repeat(None, len)), + }, + Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::FillColor(RunLengthEncoding::repeat(None, len)), + }, + ]; + + // clear borders + let sheet = self.grid.sheet_from_id(sheet_rect.sheet_id); + let borders = generate_borders( + sheet, + &sheet_rect.into(), + vec![BorderSelection::Clear], + None, + ); + ops.push(Operation::SetBorders { + sheet_rect, + borders, + }); + ops + } +} diff --git a/quadratic-core/src/controller/operations/import.rs b/quadratic-core/src/controller/operations/import.rs new file mode 100644 index 0000000000..15472841c8 --- /dev/null +++ b/quadratic-core/src/controller/operations/import.rs @@ -0,0 +1,68 @@ +use anyhow::{anyhow, bail, Result}; + +use crate::{controller::GridController, grid::SheetId, Array, CellValue, Pos, SheetRect}; + +use super::operation::Operation; + +impl GridController { + /// Imports a CSV file into the grid. + pub fn import_csv_operations( + &mut self, + sheet_id: SheetId, + file: &[u8], + file_name: &str, + insert_at: Pos, + ) -> Result> { + let error = |message: String| anyhow!("Error parsing CSV file {}: {}", file_name, message); + let width = csv::ReaderBuilder::new().from_reader(file).headers()?.len() as u32; + + if width == 0 { + bail!("empty files cannot be processed"); + } + + let mut reader = csv::ReaderBuilder::new() + .has_headers(false) + .from_reader(file); + + let mut ops = vec![] as Vec; + + let cell_values = reader + .records() + .enumerate() + .flat_map(|(row, record)| { + // convert the record into a vector of Operations + record + .map_err(|e| error(format!("line {}: {}", row + 1, e)))? + .iter() + .enumerate() + .map(|(col, value)| { + let (operations, cell_value) = self.string_to_cell_value( + (insert_at.x + col as i64, insert_at.y + row as i64, sheet_id).into(), + value, + ); + ops.extend(operations); + Ok(cell_value) + }) + .collect::>>() + }) + .collect::>>(); + + let array = Array::from(cell_values); + + let sheet_rect = SheetRect::new_pos_span( + insert_at, + ( + insert_at.x + array.width() as i64 - 1, + insert_at.y + array.height() as i64 - 1, + ) + .into(), + sheet_id, + ); + + ops.push(Operation::SetCellValues { + sheet_rect, + values: array, + }); + Ok(ops) + } +} diff --git a/quadratic-core/src/controller/operations/mod.rs b/quadratic-core/src/controller/operations/mod.rs new file mode 100644 index 0000000000..5ec5786b2c --- /dev/null +++ b/quadratic-core/src/controller/operations/mod.rs @@ -0,0 +1,13 @@ +pub mod autocomplete; +/// This module manages all Operations for GridController. +/// Functions within this directory should create Operations but should not execute them. +/// Only execute_operations should change the Grid. +/// +pub mod borders; +pub mod cell_value; +pub mod clipboard; +pub mod code_cell; +pub mod formatting; +pub mod import; +pub mod operation; +pub mod sheets; diff --git a/quadratic-core/src/controller/operation.rs b/quadratic-core/src/controller/operations/operation.rs similarity index 90% rename from quadratic-core/src/controller/operation.rs rename to quadratic-core/src/controller/operations/operation.rs index e6f5b9f483..1dcf685660 100644 --- a/quadratic-core/src/controller/operation.rs +++ b/quadratic-core/src/controller/operations/operation.rs @@ -2,24 +2,22 @@ use core::fmt; use serde::{Deserialize, Serialize}; use crate::{ - grid::{CellRef, CodeCellValue, ColumnId, RegionRef, RowId, Sheet, SheetBorders, SheetId}, - Array, + grid::{formatting::CellFmtArray, CodeCellValue, Sheet, SheetBorders, SheetId}, + Array, SheetPos, SheetRect, }; -use super::formatting::CellFmtArray; - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum Operation { SetCellValues { - region: RegionRef, + sheet_rect: SheetRect, values: Array, }, SetCellCode { - cell_ref: CellRef, + sheet_pos: SheetPos, code_cell_value: Option, }, SetCellFormats { - region: RegionRef, + sheet_rect: SheetRect, attr: CellFmtArray, }, AddSheet { @@ -29,7 +27,7 @@ pub enum Operation { sheet_id: SheetId, }, SetBorders { - region: RegionRef, + sheet_rect: SheetRect, borders: SheetBorders, }, SetSheetName { @@ -46,12 +44,12 @@ pub enum Operation { }, ResizeColumn { sheet_id: SheetId, - column: ColumnId, + column: i64, new_size: f64, }, ResizeRow { sheet_id: SheetId, - row: RowId, + row: i64, new_size: f64, }, } diff --git a/quadratic-core/src/controller/operations/sheets.rs b/quadratic-core/src/controller/operations/sheets.rs new file mode 100644 index 0000000000..9fd7b1c32b --- /dev/null +++ b/quadratic-core/src/controller/operations/sheets.rs @@ -0,0 +1,88 @@ +use itertools::Itertools; +use lexicon_fractional_index::key_between; + +use crate::{ + controller::GridController, + grid::{Sheet, SheetId}, +}; + +use super::operation::Operation; + +impl GridController { + pub fn set_sheet_name_operations(&mut self, sheet_id: SheetId, name: String) -> Vec { + vec![Operation::SetSheetName { sheet_id, name }] + } + + pub fn set_sheet_color_operations( + &mut self, + sheet_id: SheetId, + color: Option, + ) -> Vec { + vec![Operation::SetSheetColor { sheet_id, color }] + } + + pub fn add_sheet_operations(&mut self) -> Vec { + let sheet_names = &self + .grid + .sheets() + .iter() + .map(|s| s.name.as_str()) + .collect_vec(); + + let id = SheetId::new(); + let name = crate::util::unused_name("Sheet", sheet_names); + let order = self.grid.end_order(); + let sheet = Sheet::new(id, name, order); + vec![Operation::AddSheet { sheet }] + } + + pub fn delete_sheet_operations(&mut self, sheet_id: SheetId) -> Vec { + let mut operations = vec![Operation::DeleteSheet { sheet_id }]; + if self.sheet_ids().len() == 1 { + let id = SheetId::new(); + let name = String::from("Sheet 1"); + let order = self.grid.end_order(); + let sheet = Sheet::new(id, name, order); + operations.push(Operation::AddSheet { sheet }); + } + operations + } + + pub fn move_sheet_operations( + &mut self, + sheet_id: SheetId, + to_before: Option, + ) -> Vec { + // treat to_before as None if to_before's sheet no longer exists + let sheet_no_longer_exists = !self.grid.sheet_has_id(to_before); + let order = match (to_before, sheet_no_longer_exists) { + (None, true) => { + let last_order = self.grid.sheets().last().map(|last| last.order.clone()); + key_between(&last_order, &None).unwrap() + } + (Some(to_before), false) => { + let after_sheet = self.grid.sheet_from_id(to_before); + let before = self.grid.previous_sheet_order(after_sheet.id); + key_between(&before, &Some(after_sheet.order.clone())).unwrap() + } + _ => unreachable!("to_before should be None or Some"), + }; + + vec![Operation::ReorderSheet { + target: sheet_id, + order, + }] + } + + pub fn duplicate_sheet_operations(&mut self, sheet_id: SheetId) -> Vec { + let source = self.grid.sheet_from_id(sheet_id); + let mut new_sheet = self.sheet(sheet_id).clone(); + new_sheet.id = SheetId::new(); + new_sheet.name = format!("{} Copy", new_sheet.name); + let right = self.grid.next_sheet(sheet_id); + let right_order = right.map(|right| right.order.clone()); + new_sheet.order = key_between(&Some(source.order.clone()), &right_order).unwrap(); + + vec![Operation::AddSheet { sheet: new_sheet }] + } +} diff --git a/quadratic-core/src/controller/sheet_offsets.rs b/quadratic-core/src/controller/sheet_offsets.rs index e6bbb24970..40a9d2275a 100644 --- a/quadratic-core/src/controller/sheet_offsets.rs +++ b/quadratic-core/src/controller/sheet_offsets.rs @@ -1,9 +1,9 @@ use crate::{grid::SheetId, sheet_offsets::resize_transient::TransientResize}; use super::{ - operation::Operation, transaction_summary::TransactionSummary, transactions::TransactionType, - GridController, + operations::operation::Operation, transaction_summary::TransactionSummary, GridController, }; +use crate::controller::execution::TransactionType; impl GridController { /// Commits a transient resize from a local version of SheetOffsets. @@ -17,24 +17,21 @@ impl GridController { cursor: Option, ) -> TransactionSummary { if let Some(transient_resize) = transient_resize { - let sheet = self.grid.sheet_mut_from_id(sheet_id); let mut ops = vec![]; if let Some(column) = transient_resize.column { - let (column, _) = sheet.get_or_create_column(column); ops.push(Operation::ResizeColumn { sheet_id, - column: column.id, + column, new_size: transient_resize.new_size, }); } else if let Some(row) = transient_resize.row { - let row = sheet.get_or_create_row(row); ops.push(Operation::ResizeRow { sheet_id, - row: row.id, + row, new_size: transient_resize.new_size, }); } - self.set_in_progress_transaction(ops, cursor, false, TransactionType::Normal) + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) } else { TransactionSummary::default() } diff --git a/quadratic-core/src/controller/sheets.rs b/quadratic-core/src/controller/sheets.rs index 17a8b10c60..1bbf22eb59 100644 --- a/quadratic-core/src/controller/sheets.rs +++ b/quadratic-core/src/controller/sheets.rs @@ -1,13 +1,6 @@ -use itertools::Itertools; -use lexicon_fractional_index::key_between; - +use super::GridController; use crate::grid::{Sheet, SheetId}; -use super::{ - operation::Operation, transaction_summary::TransactionSummary, transactions::TransactionType, - GridController, -}; - impl GridController { pub fn sheet_ids(&self) -> Vec { self.grid.sheets().iter().map(|sheet| sheet.id).collect() @@ -15,189 +8,4 @@ impl GridController { pub fn sheet(&self, sheet_id: SheetId) -> &Sheet { self.grid.sheet_from_id(sheet_id) } - - pub fn set_sheet_name( - &mut self, - sheet_id: SheetId, - name: String, - cursor: Option, - ) -> TransactionSummary { - let operations = vec![Operation::SetSheetName { sheet_id, name }]; - self.set_in_progress_transaction(operations, cursor, false, TransactionType::Normal) - } - - pub fn set_sheet_color( - &mut self, - sheet_id: SheetId, - color: Option, - cursor: Option, - ) -> TransactionSummary { - let operations = vec![Operation::SetSheetColor { sheet_id, color }]; - self.set_in_progress_transaction(operations, cursor, false, TransactionType::Normal) - } - - pub fn add_sheet(&mut self, cursor: Option) -> TransactionSummary { - let sheet_names = &self - .grid - .sheets() - .iter() - .map(|s| s.name.as_str()) - .collect_vec(); - - let id = SheetId::new(); - let name = crate::util::unused_name("Sheet", sheet_names); - let order = self.grid.end_order(); - let sheet = Sheet::new(id, name, order); - let operations = vec![Operation::AddSheet { sheet }]; - self.set_in_progress_transaction(operations, cursor, false, TransactionType::Normal) - } - pub fn delete_sheet( - &mut self, - sheet_id: SheetId, - cursor: Option, - ) -> TransactionSummary { - let mut operations = vec![Operation::DeleteSheet { sheet_id }]; - if self.sheet_ids().len() == 1 { - let id = SheetId::new(); - let name = String::from("Sheet 1"); - let order = self.grid.end_order(); - let sheet = Sheet::new(id, name, order); - operations.push(Operation::AddSheet { sheet }); - } - self.set_in_progress_transaction(operations, cursor, false, TransactionType::Normal) - } - pub fn move_sheet( - &mut self, - sheet_id: SheetId, - to_before: Option, - cursor: Option, - ) -> TransactionSummary { - // treat to_before as None if to_before's sheet no longer exists - let sheet_no_longer_exists = !self.grid.sheet_has_id(to_before); - let order = match (to_before, sheet_no_longer_exists) { - (None, true) => { - let last_order = self.grid.sheets().last().map(|last| last.order.clone()); - key_between(&last_order, &None).unwrap() - } - (Some(to_before), false) => { - let after_sheet = self.grid.sheet_from_id(to_before); - let before = self.grid.previous_sheet_order(after_sheet.id); - key_between(&before, &Some(after_sheet.order.clone())).unwrap() - } - _ => unreachable!("to_before should be None or Some"), - }; - - let operations = vec![Operation::ReorderSheet { - target: sheet_id, - order, - }]; - self.set_in_progress_transaction(operations, cursor, false, TransactionType::Normal) - } - pub fn duplicate_sheet( - &mut self, - sheet_id: SheetId, - cursor: Option, - ) -> TransactionSummary { - let source = self.grid.sheet_from_id(sheet_id); - let mut new_sheet = self.sheet(sheet_id).clone(); - new_sheet.id = SheetId::new(); - new_sheet.name = format!("{} Copy", new_sheet.name); - let right = self.grid.next_sheet(sheet_id); - let right_order = right.map(|right| right.order.clone()); - new_sheet.order = key_between(&Some(source.order.clone()), &right_order).unwrap(); - let operations = vec![Operation::AddSheet { sheet: new_sheet }]; - self.set_in_progress_transaction(operations, cursor, false, TransactionType::Normal) - } -} - -#[cfg(test)] -mod test { - use crate::{controller::GridController, grid::SheetId}; - - #[test] - fn test_add_delete_reorder_sheets() { - let mut g = GridController::new(); - g.add_sheet(None); - g.add_sheet(None); - let old_sheet_ids = g.sheet_ids(); - let s1 = old_sheet_ids[0]; - let s2 = old_sheet_ids[1]; - let s3 = old_sheet_ids[2]; - - fn test_reorder( - g: &mut GridController, - a: SheetId, - b: Option, - expected: [SheetId; 3], - old_sheet_ids: &Vec, - ) { - g.move_sheet(a, b, None); - assert_eq!(expected.to_vec(), g.sheet_ids()); - g.undo(None); - assert_eq!(*old_sheet_ids, g.sheet_ids()); - } - - test_reorder(&mut g, s1, Some(s2), [s1, s2, s3], &old_sheet_ids); - test_reorder(&mut g, s1, Some(s3), [s2, s1, s3], &old_sheet_ids); - test_reorder(&mut g, s1, None, [s2, s3, s1], &old_sheet_ids); - test_reorder(&mut g, s2, Some(s1), [s2, s1, s3], &old_sheet_ids); - test_reorder(&mut g, s2, Some(s3), [s1, s2, s3], &old_sheet_ids); - test_reorder(&mut g, s2, None, [s1, s3, s2], &old_sheet_ids); - test_reorder(&mut g, s3, Some(s1), [s3, s1, s2], &old_sheet_ids); - test_reorder(&mut g, s3, Some(s2), [s1, s3, s2], &old_sheet_ids); - test_reorder(&mut g, s3, None, [s1, s2, s3], &old_sheet_ids); - - fn test_delete( - g: &mut GridController, - a: SheetId, - expected: [SheetId; 2], - old_sheet_ids: &Vec, - ) { - g.delete_sheet(a, None); - assert_eq!(expected.to_vec(), g.sheet_ids()); - g.undo(None); - assert_eq!(*old_sheet_ids, g.sheet_ids()); - } - - test_delete(&mut g, s1, [s2, s3], &old_sheet_ids); - test_delete(&mut g, s2, [s1, s3], &old_sheet_ids); - test_delete(&mut g, s3, [s1, s2], &old_sheet_ids); - } - - #[test] - fn test_duplicate_sheet() { - let mut g = GridController::new(); - let old_sheet_ids = g.sheet_ids(); - let s1 = old_sheet_ids[0]; - - g.set_sheet_name(s1, String::from("Nice Name"), None); - g.duplicate_sheet(s1, None); - let sheet_ids = g.sheet_ids(); - let s2 = sheet_ids[1]; - - let sheet1 = g.sheet(s1); - let sheet2 = g.sheet(s2); - - assert_eq!(sheet2.name, format!("{} Copy", sheet1.name)); - } - - #[test] - fn test_delete_last_sheet() { - let mut g = GridController::new(); - let sheet_ids = g.sheet_ids(); - let first_sheet_id = sheet_ids[0]; - - g.delete_sheet(first_sheet_id, None); - let new_sheet_ids = g.sheet_ids(); - assert_eq!(new_sheet_ids.len(), 1); - assert_ne!(new_sheet_ids[0], sheet_ids[0]); - - g.undo(None); - let new_sheet_ids_2 = g.sheet_ids(); - assert_eq!(sheet_ids[0], new_sheet_ids_2[0]); - - g.redo(None); - let new_sheet_ids_3 = g.sheet_ids(); - assert_eq!(new_sheet_ids[0], new_sheet_ids_3[0]); - } } diff --git a/quadratic-core/src/controller/spills.rs b/quadratic-core/src/controller/spills.rs index 6662377a06..8391627c6d 100644 --- a/quadratic-core/src/controller/spills.rs +++ b/quadratic-core/src/controller/spills.rs @@ -1,36 +1,18 @@ -use indexmap::IndexSet; - -use crate::{ - controller::{ - transaction_summary::TransactionSummary, update_code_cell_value::update_code_cell_value, - GridController, - }, - grid::CellRef, -}; - -use super::operation::Operation; +use crate::{controller::GridController, SheetPos}; impl GridController { - pub fn check_spill( - &mut self, - cell_ref: CellRef, - cells_to_compute: &mut IndexSet, - summary: &mut TransactionSummary, - reverse_operations: &mut Vec, - ) { + /// Checks whether a spill exists + pub fn check_spill(&mut self, sheet_pos: SheetPos) { + let sheet_id = sheet_pos.sheet_id; // check if the addition of a cell causes a spill error - let sheet = self.grid.sheet_from_id(cell_ref.sheet); - if let Some(code_cell_ref) = sheet.get_spill(cell_ref) { - if code_cell_ref != cell_ref { - if let Some(code_cell) = sheet.get_code_cell_from_ref(code_cell_ref) { + let sheet = self.grid.sheet_from_id(sheet_id); + if let Some(code_cell_pos) = sheet.get_spill(sheet_pos.into()) { + if code_cell_pos != sheet_pos.into() { + if let Some(code_cell) = sheet.get_code_cell(code_cell_pos) { if !code_cell.has_spill_error() { - update_code_cell_value( - self, - code_cell_ref, + self.update_code_cell_value( + code_cell_pos.to_sheet_pos(sheet_id), Some(code_cell.clone()), - cells_to_compute, - reverse_operations, - summary, ); } } @@ -38,50 +20,22 @@ impl GridController { } } - // TODO(ddimaria): implement many of the below functions in TransactionInProgress - // then we can just reference self - /// sets a spill error for a code_cell - pub fn set_spill_error( - &mut self, - cell_ref: CellRef, - cells_to_compute: &mut IndexSet, - summary: &mut TransactionSummary, - reverse_operations: &mut Vec, - ) { - let sheet = self.grid.sheet_from_id(cell_ref.sheet); - if let Some(code_cell) = sheet.get_code_cell_from_ref(cell_ref) { + pub fn set_spill_error(&mut self, sheet_pos: SheetPos) { + let sheet = self.grid.sheet_from_id(sheet_pos.sheet_id); + if let Some(code_cell) = sheet.get_code_cell(sheet_pos.into()) { if !code_cell.has_spill_error() { - update_code_cell_value( - self, - cell_ref, - Some(code_cell.clone()), - cells_to_compute, - reverse_operations, - summary, - ); + self.update_code_cell_value(sheet_pos, Some(code_cell.clone())); } } } /// update the code cell value if the deletion of a cell released a spill error - pub fn update_code_cell_value_if_spill_error_released( - &mut self, - cell_ref: CellRef, - cells_to_compute: &mut IndexSet, - summary: &mut TransactionSummary, - reverse_operations: &mut Vec, - ) { - let sheet = self.grid.sheet_from_id(cell_ref.sheet); - if let Some((cell_ref, code_cell)) = sheet.spill_error_released(cell_ref) { - update_code_cell_value( - self, - cell_ref, - Some(code_cell), - cells_to_compute, - reverse_operations, - summary, - ); + pub fn update_code_cell_value_if_spill_error_released(&mut self, sheet_pos: SheetPos) { + let sheet_id = sheet_pos.sheet_id; + let sheet = self.grid.sheet_from_id(sheet_id); + if let Some((spill_sheet_pos, code_cell)) = sheet.spill_error_released(sheet_pos.into()) { + self.update_code_cell_value(spill_sheet_pos.to_sheet_pos(sheet_id), Some(code_cell)); } } } @@ -91,7 +45,7 @@ mod test { use crate::{ controller::GridController, grid::{js_types::JsRenderCell, CellAlign, CodeCellLanguage}, - Pos, Rect, + Pos, Rect, SheetPos, }; fn output_spill_error(x: i64, y: i64) -> Vec { @@ -133,15 +87,50 @@ mod test { let sheet_id = gc.grid.sheet_ids()[0]; // values to copy - gc.set_cell_value(sheet_id, Pos { x: 1, y: 0 }, "1".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 1, y: 1 }, "2".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 1, y: 2 }, "3".into(), None); + gc.set_cell_value( + SheetPos { + x: 1, + y: 0, + sheet_id, + }, + "1".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 1, + y: 1, + sheet_id, + }, + "2".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 1, + y: 2, + sheet_id, + }, + "3".into(), + None, + ); // value to cause the spill - gc.set_cell_value(sheet_id, Pos { x: 0, y: 1 }, "hello".into(), None); + gc.set_cell_value( + SheetPos { + x: 0, + y: 1, + sheet_id, + }, + "hello".into(), + None, + ); gc.set_cell_code( - sheet_id, - Pos { x: 0, y: 0 }, + SheetPos { + x: 0, + y: 0, + sheet_id, + }, CodeCellLanguage::Formula, "B0:B3".into(), None, @@ -153,7 +142,15 @@ mod test { assert_eq!(render_cells, output_spill_error(0, 0),); // remove 'hello' that caused spill - gc.set_cell_value(sheet_id, Pos { x: 0, y: 1 }, "".into(), None); + gc.set_cell_value( + SheetPos { + x: 0, + y: 1, + sheet_id, + }, + "".into(), + None, + ); let sheet = gc.grid.sheet_from_id(sheet_id); let render_cells = sheet.get_render_cells(Rect::single_pos(Pos { x: 0, y: 0 })); @@ -171,14 +168,41 @@ mod test { let sheet_id = gc.grid.sheet_ids()[0]; // values to copy - gc.set_cell_value(sheet_id, Pos { x: 1, y: 0 }, "1".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 1, y: 1 }, "2".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 1, y: 2 }, "3".into(), None); + gc.set_cell_value( + SheetPos { + x: 1, + y: 0, + sheet_id, + }, + "1".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 1, + y: 1, + sheet_id, + }, + "2".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 1, + y: 2, + sheet_id, + }, + "3".into(), + None, + ); // value to cause the spill gc.set_cell_code( - sheet_id, - Pos { x: 0, y: 0 }, + SheetPos { + x: 0, + y: 0, + sheet_id, + }, CodeCellLanguage::Formula, "B0:B3".into(), None, @@ -194,8 +218,11 @@ mod test { assert_eq!(render_cells, output_number(0, 1, "2", None),); gc.set_cell_code( - sheet_id, - Pos { x: 0, y: 1 }, + SheetPos { + x: 0, + y: 1, + sheet_id, + }, CodeCellLanguage::Formula, "1 + 2".into(), None, @@ -213,20 +240,95 @@ mod test { let sheet_id = gc.grid.sheet_ids()[0]; // values to copy - gc.set_cell_value(sheet_id, Pos { x: 0, y: 0 }, "1".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 0, y: 1 }, "2".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 0, y: 2 }, "3".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 1, y: 0 }, "1".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 1, y: 1 }, "2".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 1, y: 2 }, "3".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 2, y: 0 }, "1".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 2, y: 1 }, "2".into(), None); - gc.set_cell_value(sheet_id, Pos { x: 2, y: 2 }, "3".into(), None); + gc.set_cell_value( + SheetPos { + x: 0, + y: 0, + sheet_id, + }, + "1".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 0, + y: 1, + sheet_id, + }, + "2".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 0, + y: 2, + sheet_id, + }, + "3".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 1, + y: 0, + sheet_id, + }, + "1".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 1, + y: 1, + sheet_id, + }, + "2".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 1, + y: 2, + sheet_id, + }, + "3".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 2, + y: 0, + sheet_id, + }, + "1".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 2, + y: 1, + sheet_id, + }, + "2".into(), + None, + ); + gc.set_cell_value( + SheetPos { + x: 2, + y: 2, + sheet_id, + }, + "3".into(), + None, + ); // copies values to copy to 10,10 gc.set_cell_code( - sheet_id, - Pos { x: 10, y: 10 }, + SheetPos { + x: 10, + y: 10, + sheet_id, + }, CodeCellLanguage::Formula, "A0:C2".into(), None, @@ -234,8 +336,11 @@ mod test { // output that is spilled gc.set_cell_code( - sheet_id, - Pos { x: 11, y: 9 }, + SheetPos { + x: 11, + y: 9, + sheet_id, + }, CodeCellLanguage::Formula, "A0:A2".into(), None, @@ -246,7 +351,15 @@ mod test { assert_eq!(render_cells, output_spill_error(11, 9)); // delete the code_cell that caused the spill - gc.set_cell_value(sheet_id, Pos { x: 10, y: 10 }, "".into(), None); + gc.set_cell_value( + SheetPos { + x: 10, + y: 10, + sheet_id, + }, + "".into(), + None, + ); let sheet = gc.grid.sheet_from_id(sheet_id); let render_cells = sheet.get_render_cells(Rect::single_pos(Pos { x: 11, y: 9 })); diff --git a/quadratic-core/src/controller/thumbnail.rs b/quadratic-core/src/controller/thumbnail.rs index f55138845b..4846f10e9d 100644 --- a/quadratic-core/src/controller/thumbnail.rs +++ b/quadratic-core/src/controller/thumbnail.rs @@ -1,116 +1,93 @@ -use crate::{ - grid::{RegionRef, SheetId}, - Pos, Rect, -}; +use crate::{SheetPos, SheetRect}; use super::GridController; impl GridController { - /// whether the thumbnail needs to be updated for this region - pub fn thumbnail_dirty_region(&self, region: &RegionRef) -> bool { - if region.sheet != self.grid().first_sheet_id() { - return false; - } - let sheet = self.sheet(region.sheet); - region.iter().any(|cell_ref| { - if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { - self.thumbnail_dirty_pos(region.sheet, pos) - } else { - false - } - }) - } - /// whether the thumbnail needs to be updated for this Pos - pub fn thumbnail_dirty_pos(&self, sheet_id: SheetId, pos: Pos) -> bool { - self.thumbnail_dirty_rect(sheet_id, Rect::single_pos(pos)) + pub fn thumbnail_dirty_sheet_pos(&self, sheet_pos: SheetPos) -> bool { + self.thumbnail_dirty_sheet_rect(sheet_pos.into()) } /// whether the thumbnail needs to be updated for this rectangle - pub fn thumbnail_dirty_rect(&self, sheet_id: SheetId, rect: Rect) -> bool { - if sheet_id != self.grid().first_sheet_id() { + pub fn thumbnail_dirty_sheet_rect(&self, sheet_rect: SheetRect) -> bool { + if sheet_rect.sheet_id != self.grid().first_sheet_id() { return false; } - let sheet = self.sheet(sheet_id); - rect.intersects(sheet.offsets.thumbnail()) + let sheet = self.sheet(sheet_rect.sheet_id); + sheet_rect.intersects(sheet.offsets.thumbnail().to_sheet_rect(sheet_rect.sheet_id)) } } #[cfg(test)] mod test { - use crate::{controller::GridController, Pos, Rect, THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH}; + use crate::{ + controller::GridController, Pos, SheetPos, SheetRect, THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH, + }; #[test] fn test_thumbnail_dirty_pos() { let gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; - assert!(gc.thumbnail_dirty_pos(sheet_id, Pos { x: 0, y: 0 })); - assert!(!gc.thumbnail_dirty_pos( - sheet_id, - Pos { - x: (THUMBNAIL_WIDTH as i64) + 1i64, - y: 0 - } - )); - assert!(!gc.thumbnail_dirty_pos( - sheet_id, - Pos { - x: 0, - y: (THUMBNAIL_HEIGHT as i64) + 1i64, - } - )); - assert!(!gc.thumbnail_dirty_pos( - sheet_id, - Pos { - x: THUMBNAIL_WIDTH as i64, - y: THUMBNAIL_HEIGHT as i64, - } - )); + assert!(gc.thumbnail_dirty_sheet_pos(SheetPos { + x: 0, + y: 0, + sheet_id + })); + assert!(!gc.thumbnail_dirty_sheet_pos(SheetPos { + x: (THUMBNAIL_WIDTH as i64) + 1i64, + y: 0, + sheet_id + })); + assert!(!gc.thumbnail_dirty_sheet_pos(SheetPos { + x: 0, + y: (THUMBNAIL_HEIGHT as i64) + 1i64, + sheet_id + })); + assert!(!gc.thumbnail_dirty_sheet_pos(SheetPos { + x: THUMBNAIL_WIDTH as i64, + y: THUMBNAIL_HEIGHT as i64, + sheet_id + })); } #[test] fn test_thumbnail_dirty_rect() { let gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; - assert!(gc.thumbnail_dirty_rect( + assert!(gc.thumbnail_dirty_sheet_rect(SheetRect { + min: Pos { x: 0, y: 0 }, + max: Pos { x: 1, y: 1 }, sheet_id, - Rect { - min: Pos { x: 0, y: 0 }, - max: Pos { x: 1, y: 1 } - } - )); - assert!(!gc.thumbnail_dirty_rect( - sheet_id, - Rect { - min: Pos { - x: (THUMBNAIL_WIDTH as i64) + 1i64, - y: 0 - }, - max: Pos { - x: (THUMBNAIL_WIDTH as i64) + 10i64, - y: 0 - } - } - )); - assert!(!gc.thumbnail_dirty_rect( + })); + assert!(!gc.thumbnail_dirty_sheet_rect(SheetRect { + min: Pos { + x: (THUMBNAIL_WIDTH as i64) + 1i64, + y: 0 + }, + max: Pos { + x: (THUMBNAIL_WIDTH as i64) + 10i64, + y: 0 + }, sheet_id, - Rect { - min: Pos { - x: 0, - y: (THUMBNAIL_HEIGHT as i64) + 1i64, - }, - max: Pos { - x: 0, - y: (THUMBNAIL_HEIGHT as i64) + 10i64, - } - } - )); - assert!(!gc.thumbnail_dirty_rect( + })); + assert!(!gc.thumbnail_dirty_sheet_rect(SheetRect { + min: Pos { + x: 0, + y: (THUMBNAIL_HEIGHT as i64) + 1i64, + }, + max: Pos { + x: 0, + y: (THUMBNAIL_HEIGHT as i64) + 10i64, + }, sheet_id, - Rect::single_pos(Pos { + })); + assert!(!gc.thumbnail_dirty_sheet_rect( + SheetPos { x: THUMBNAIL_WIDTH as i64, y: THUMBNAIL_HEIGHT as i64, - }), + sheet_id + } + .into(), )); } } diff --git a/quadratic-core/src/controller/transaction_summary.rs b/quadratic-core/src/controller/transaction_summary.rs index bee4d45ac7..02dd0c98ef 100644 --- a/quadratic-core/src/controller/transaction_summary.rs +++ b/quadratic-core/src/controller/transaction_summary.rs @@ -2,10 +2,9 @@ use std::collections::HashSet; use serde::{Deserialize, Serialize}; -use crate::{ - grid::{RegionRef, Sheet, SheetId}, - Pos, -}; +use crate::{grid::SheetId, SheetPos, SheetRect}; + +use super::GridController; // keep this in sync with CellsTypes.ts pub const CELL_SHEET_WIDTH: u32 = 20; @@ -20,27 +19,15 @@ pub struct CellSheetsModified { } impl CellSheetsModified { - pub fn new(sheet_id: SheetId, pos: Pos) -> Self { - let x = (pos.x as f64 / CELL_SHEET_WIDTH as f64).floor() as i32; - let y = (pos.y as f64 / CELL_SHEET_HEIGHT as f64).floor() as i32; + pub fn new(sheet_pos: SheetPos) -> Self { + let x = (sheet_pos.x as f64 / CELL_SHEET_WIDTH as f64).floor() as i32; + let y = (sheet_pos.y as f64 / CELL_SHEET_HEIGHT as f64).floor() as i32; Self { - sheet_id: sheet_id.to_string(), + sheet_id: sheet_pos.sheet_id.to_string(), x, y, } } - - pub fn add_region( - cells_sheet_modified: &mut HashSet, - sheet: &Sheet, - region: &RegionRef, - ) { - region.iter().for_each(|cell_ref| { - if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { - cells_sheet_modified.insert(Self::new(sheet.id, pos)); - } - }); - } } #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)] @@ -76,6 +63,9 @@ pub struct TransactionSummary { // should the grid generate a thumbnail pub generate_thumbnail: bool, + // holds the operations to be shared via multiplayer + pub forward_operations: Option, + // changes to html output pub html: HashSet, } @@ -88,7 +78,7 @@ impl TransactionSummary { } } - pub fn clear(&mut self) { + pub fn clear(&mut self, keep_forward_operations: bool) { self.fill_sheets_modified.clear(); self.border_sheets_modified.clear(); self.code_cells_modified.clear(); @@ -98,6 +88,101 @@ impl TransactionSummary { self.cursor = None; self.transaction_busy = false; self.generate_thumbnail = false; - self.save = true; + self.save = false; + if !keep_forward_operations { + self.forward_operations = None; + } + } +} + +impl GridController { + pub fn add_cell_sheets_modified_rect(&mut self, sheet_rect: &SheetRect) { + let mut modified = HashSet::new(); + for y in sheet_rect.y_range() { + for x in sheet_rect.x_range() { + let sheet_pos = SheetPos { + x, + y, + sheet_id: sheet_rect.sheet_id, + }; + modified.insert(CellSheetsModified::new(sheet_pos)); + } + } + + let summary = &mut self.summary; + summary.cell_sheets_modified.extend(modified); + } +} + +#[cfg(test)] +mod tests { + use crate::{controller::GridController, Rect}; + + use super::*; + + #[test] + fn test_cell_sheets_modified() { + let sheet_id = SheetId::new(); + let cell_sheets_modified = CellSheetsModified::new(SheetPos { + sheet_id, + x: 0, + y: 0, + }); + assert_eq!( + cell_sheets_modified, + CellSheetsModified { + sheet_id: sheet_id.to_string(), + x: 0, + y: 0 + } + ); + } + + fn has_cell_sheet( + cell_sheets_modified: &HashSet, + sheet_id: SheetId, + x: i32, + y: i32, + ) -> bool { + cell_sheets_modified.iter().any(|modified| { + print!( + "{}: ({}, {}) == {}: ({}, {})", + modified.sheet_id, modified.x, modified.y, sheet_id, x, y + ); + modified.sheet_id == sheet_id.to_string() && modified.x == x && modified.y == y + }) + } + + #[test] + fn test_cell_sheets_modified_region() { + let mut gc = GridController::new(); + let sheet_id = gc.grid().first_sheet_id(); + let sheet_rect = Rect::from_numbers(0, 0, 21, 41).to_sheet_rect(sheet_id); + gc.add_cell_sheets_modified_rect(&sheet_rect); + assert_eq!(gc.summary.cell_sheets_modified.len(), 4); + assert!(has_cell_sheet( + &gc.summary.cell_sheets_modified, + sheet_id, + 0, + 0 + )); + assert!(has_cell_sheet( + &gc.summary.cell_sheets_modified, + sheet_id, + 0, + 1 + )); + assert!(has_cell_sheet( + &gc.summary.cell_sheets_modified, + sheet_id, + 1, + 0 + )); + assert!(has_cell_sheet( + &gc.summary.cell_sheets_modified, + sheet_id, + 1, + 1 + )); } } diff --git a/quadratic-core/src/controller/transaction_types.rs b/quadratic-core/src/controller/transaction_types.rs index 095b0e0d6e..1ba4dd92c3 100644 --- a/quadratic-core/src/controller/transaction_types.rs +++ b/quadratic-core/src/controller/transaction_types.rs @@ -1,13 +1,11 @@ use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::wasm_bindgen; -use crate::{ - grid::{CellRef, CodeCellLanguage, CodeCellRunOutput, CodeCellRunResult, CodeCellValue, Sheet}, - util::date_string, - Array, CellValue, Error, ErrorMsg, Pos, Rect, Span, Value, -}; +use crate::{Pos, Rect}; -use super::operation::Operation; +// todo: CellsForArray should be ts-rs type instead of rust type. +// It should be renamed to something more meaningful. +// TransactionResponse by js_calculation_get_cells instead of requiring a separate call. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[wasm_bindgen] @@ -50,6 +48,7 @@ impl CellForArray { pub struct CellsForArray { cells: Vec, i: usize, + // todo: this should be the Option pub transaction_response: bool, } @@ -82,6 +81,7 @@ impl CellsForArray { } } +// todo: this should also be reworked with ts-rs #[wasm_bindgen] pub struct JsCodeResult { success: bool, @@ -95,64 +95,49 @@ pub struct JsCodeResult { } impl JsCodeResult { - pub fn into_code_cell_value( - &self, - sheet: &mut Sheet, - start: CellRef, - language: CodeCellLanguage, - code_string: String, - cells_accessed: &Vec, - reverse_operations: &mut Vec, - ) -> CodeCellValue { - let result = if self.success { - CodeCellRunResult::Ok { - output_value: if let Some(array_output) = self.array_output.to_owned() { - let (array, ops) = Array::from_string_list(start, sheet, array_output); - reverse_operations.extend(ops); - if let Some(array) = array { - Value::Array(array) - } else { - Value::Single("".into()) - } - } else if let Some(output_value) = self.output_value.as_ref() { - let cell_ref = CellRef { - sheet: sheet.id, - column: start.column, - row: start.row, - }; - let (cell_value, ops) = CellValue::from_string(output_value, cell_ref, sheet); - reverse_operations.extend(ops); - Value::Single(cell_value) - } else { - unreachable!() - }, - cells_accessed: cells_accessed.to_owned(), - } - } else { - let error_msg = self - .error_msg - .to_owned() - .unwrap_or_else(|| "Unknown Python Error".into()); - let msg = ErrorMsg::PythonError(error_msg.into()); - let span = self.line_number.map(|line_number| Span { - start: line_number, - end: line_number, - }); - CodeCellRunResult::Err { - error: Error { span, msg }, - } - }; - CodeCellValue { - language, - code_string, - formatted_code_string: self.formatted_code.clone(), - output: Some(CodeCellRunOutput { - std_out: self.input_python_std_out.clone(), - std_err: self.error_msg.clone(), - result, - spill: false, - }), - last_modified: date_string(), + pub fn success(&self) -> bool { + self.success + } + pub fn output_value(&self) -> Option { + self.output_value.clone() + } + pub fn array_output(&self) -> Option>> { + self.array_output.clone() + } + pub fn error_msg(&self) -> Option { + self.error_msg.clone() + } + pub fn line_number(&self) -> Option { + self.line_number + } + pub fn formatted_code(&self) -> Option { + self.formatted_code.clone() + } + pub fn input_python_std_out(&self) -> Option { + self.input_python_std_out.clone() + } + + #[cfg(test)] + #[allow(clippy::too_many_arguments)] + pub fn new_from_rust( + success: bool, + formatted_code: Option, + error_msg: Option, + input_python_std_out: Option, + output_value: Option, + array_output: Option>>, + line_number: Option, + cancel_compute: Option, + ) -> Self { + JsCodeResult { + success, + formatted_code, + error_msg, + input_python_std_out, + output_value, + array_output, + line_number, + cancel_compute, } } } @@ -224,117 +209,3 @@ impl JsComputeGetCells { self.line_number } } - -#[cfg(test)] -mod test { - use std::str::FromStr; - - use bigdecimal::BigDecimal; - - use crate::{ - controller::{operation::Operation, transaction_types::JsCodeResult, GridController}, - grid::{CodeCellLanguage, CodeCellRunOutput}, - Array, ArraySize, CellValue, Pos, Value, - }; - - #[test] - fn test_into_code_cell_value_single() { - let mut gc = GridController::new(); - let sheet_id = gc.sheet_ids()[0]; - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_id); - let result = JsCodeResult { - success: true, - formatted_code: None, - error_msg: None, - input_python_std_out: None, - output_value: Some("$12".into()), - array_output: None, - line_number: None, - cancel_compute: None, - }; - - let cell_ref = sheet.get_or_create_cell_ref(Pos { x: 0, y: 0 }); - let mut ops: Vec = vec![]; - assert_eq!( - result - .into_code_cell_value( - sheet, - cell_ref, - CodeCellLanguage::Python, - "".into(), - &vec![], - &mut ops - ) - .output, - Some(CodeCellRunOutput { - std_out: None, - std_err: None, - result: crate::grid::CodeCellRunResult::Ok { - output_value: Value::Single(CellValue::Number(12.into())), - cells_accessed: vec![] - }, - spill: false, - }), - ); - assert_eq!(ops.len(), 2); - } - - #[test] - fn test_into_code_cell_value_array() { - let mut gc = GridController::new(); - let sheet_id = gc.sheet_ids()[0]; - let sheet = gc.grid_mut().sheet_mut_from_id(sheet_id); - let array_output: Vec> = vec![ - vec!["$1.1".into(), "20%".into()], - vec!["3".into(), "Hello".into()], - ]; - let result = JsCodeResult { - success: true, - formatted_code: None, - error_msg: None, - input_python_std_out: None, - output_value: None, - array_output: Some(array_output), - line_number: None, - cancel_compute: None, - }; - - let cell_ref = sheet.get_or_create_cell_ref(Pos { x: 0, y: 0 }); - let mut ops: Vec = vec![]; - let mut array = Array::new_empty(ArraySize::new(2, 2).unwrap()); - let _ = array.set( - 0, - 0, - CellValue::Number(BigDecimal::from_str("1.1").unwrap()), - ); - let _ = array.set( - 1, - 0, - CellValue::Number(BigDecimal::from_str("0.2").unwrap()), - ); - let _ = array.set(0, 1, CellValue::Number(BigDecimal::from_str("3").unwrap())); - let _ = array.set(1, 1, CellValue::Text("Hello".into())); - assert_eq!( - result - .into_code_cell_value( - sheet, - cell_ref, - CodeCellLanguage::Python, - "".into(), - &vec![], - &mut ops - ) - .output, - Some(CodeCellRunOutput { - std_out: None, - std_err: None, - result: crate::grid::CodeCellRunResult::Ok { - output_value: Value::Array(array), - cells_accessed: vec![] - }, - spill: false, - }), - ); - assert_eq!(ops.len(), 3); - } -} diff --git a/quadratic-core/src/controller/transactions.rs b/quadratic-core/src/controller/transactions.rs deleted file mode 100644 index 782ae784a7..0000000000 --- a/quadratic-core/src/controller/transactions.rs +++ /dev/null @@ -1,334 +0,0 @@ -use core::panic; - -use crate::{computation::TransactionInProgress, Pos}; -use serde::{Deserialize, Serialize}; - -use super::{ - operation::Operation, - transaction_summary::{TransactionSummary, CELL_SHEET_HEIGHT, CELL_SHEET_WIDTH}, - transaction_types::{CellsForArray, JsCodeResult, JsComputeGetCells}, - GridController, -}; - -#[derive(Default, Debug, Serialize, Deserialize, Clone)] -pub enum TransactionType { - #[default] - Normal, - Undo, - Redo, -} - -impl GridController { - pub fn finalize_transaction(&mut self, transaction_in_progress: &TransactionInProgress) { - let transaction: Transaction = transaction_in_progress.into(); - match transaction_in_progress.transaction_type { - TransactionType::Normal => { - self.undo_stack.push(transaction); - self.redo_stack.clear(); - } - TransactionType::Undo => { - self.redo_stack.push(transaction); - } - TransactionType::Redo => { - self.undo_stack.push(transaction); - } - } - } - - pub fn set_in_progress_transaction( - &mut self, - operations: Vec, - cursor: Option, - compute: bool, - transaction_type: TransactionType, - ) -> TransactionSummary { - if self - .transaction_in_progress - .as_ref() - .is_some_and(|in_progress_transaction| !in_progress_transaction.complete) - { - // todo: add this to a queue of operations instead of setting the busy flag - return TransactionSummary::new(true); - } - let mut transaction = TransactionInProgress::start_transaction( - self, - operations, - cursor, - compute, - transaction_type, - ); - let mut summary = transaction.transaction_summary(); - transaction.updated_bounds(self); - - if transaction.complete { - summary.save = true; - self.finalize_transaction(&transaction); - } else { - self.transaction_in_progress = Some(transaction); - } - summary - } - - pub fn has_undo(&self) -> bool { - !self.undo_stack.is_empty() - } - pub fn has_redo(&self) -> bool { - !self.redo_stack.is_empty() - } - pub fn undo(&mut self, cursor: Option) -> TransactionSummary { - if let Some(transaction) = self.undo_stack.pop() { - let mut summary = self.set_in_progress_transaction( - transaction.ops, - cursor, - false, - TransactionType::Undo, - ); - summary.cursor = transaction.cursor; - summary - } else { - TransactionSummary::default() - } - } - pub fn redo(&mut self, cursor: Option) -> TransactionSummary { - if let Some(transaction) = self.redo_stack.pop() { - let mut summary = self.set_in_progress_transaction( - transaction.ops, - cursor, - false, - TransactionType::Redo, - ); - summary.cursor = transaction.cursor; - summary - } else { - TransactionSummary::default() - } - } - pub fn calculation_complete(&mut self, result: JsCodeResult) -> TransactionSummary { - // todo: there's probably a better way to do this - if let Some(transaction) = &mut self.transaction_in_progress.clone() { - let cancel_compute = result.cancel_compute.unwrap_or(false); - - if cancel_compute { - transaction.clear_cells_to_compute(); - transaction.loop_compute(self); - } - - transaction.calculation_complete(self, result); - self.transaction_in_progress = Some(transaction.to_owned()); - - transaction.updated_bounds(self); - if transaction.complete { - transaction.transaction_summary() - } else { - TransactionSummary::default() - } - } else { - panic!("Expected an in progress transaction"); - } - } - - /// This is used to get cells during a TS-controlled async calculation - pub fn calculation_get_cells(&mut self, get_cells: JsComputeGetCells) -> Option { - // todo: there's probably a better way to do this - the clone is necessary b/c get_cells needs a mutable grid as well - if let Some(transaction) = &mut self.transaction_in_progress.clone() { - let result = transaction.get_cells(self, get_cells); - self.transaction_in_progress = Some(transaction.to_owned()); - result - } else { - panic!("Expected a transaction to still be running"); - } - } - - /// Creates a TransactionSummary and cleans - /// Note: it may not pass cells_sheet_modified if the transaction is not complete (to avoid redrawing cells multiple times) - pub fn transaction_summary(&mut self) -> Option { - // let skip_cell_rendering = self - // .transaction_in_progress - // .as_ref() - // .is_some_and(|transaction| !transaction.complete); - self.transaction_in_progress - .as_mut() - .map(|transaction| transaction.transaction_summary()) - } - - pub fn updated_bounds_in_transaction(&mut self) { - if let Some(transaction) = &mut self.transaction_in_progress.clone() { - transaction.updated_bounds(self); - self.transaction_in_progress = Some(transaction.to_owned()); - } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Transaction { - pub ops: Vec, - pub cursor: Option, -} - -#[derive(Debug, PartialEq)] -pub struct CellHash(String); - -impl CellHash { - pub fn get(&self) -> String { - self.0.clone() - } -} - -impl From for CellHash { - fn from(pos: Pos) -> Self { - let hash_width = CELL_SHEET_WIDTH as f64; - let hash_height = CELL_SHEET_HEIGHT as f64; - let cell_hash_x = (pos.x as f64 / hash_width).floor() as i64; - let cell_hash_y = (pos.y as f64 / hash_height).floor() as i64; - let cell_hash = format!("{},{}", cell_hash_x, cell_hash_y); - - CellHash(cell_hash) - } -} - -#[cfg(test)] -mod tests { - use crate::{ - grid::{GridBounds, SheetId}, - Array, CellValue, Pos, Rect, - }; - - use super::*; - - fn add_cell_value( - gc: &mut GridController, - sheet_id: SheetId, - pos: Pos, - value: CellValue, - ) -> Operation { - let rect = Rect::new_span(pos, pos); - let region = gc.region(sheet_id, rect); - - Operation::SetCellValues { - region, - values: Array::from(value), - } - } - - fn get_operations(gc: &mut GridController) -> (Operation, Operation) { - let sheet_id = gc.sheet_ids()[0]; - let pos = Pos::from((0, 0)); - let value = CellValue::Text("test".into()); - let operation = add_cell_value(gc, sheet_id, pos, value); - let operation_undo = add_cell_value(gc, sheet_id, pos, CellValue::Blank); - - (operation, operation_undo) - } - - #[test] - fn test_transactions_finalize_transaction() { - let mut gc = GridController::new(); - let (operation, operation_undo) = get_operations(&mut gc); - - // TransactionType::Normal - let transaction_in_progress = TransactionInProgress::start_transaction( - &mut gc, - vec![operation.clone()], - None, - false, - TransactionType::Normal, - ); - gc.finalize_transaction(&transaction_in_progress); - - assert_eq!(gc.undo_stack.len(), 1); - assert_eq!(gc.redo_stack.len(), 0); - assert_eq!(vec![operation_undo.clone()], gc.undo_stack[0].ops); - - // TransactionType::Undo - let transaction_in_progress = TransactionInProgress::start_transaction( - &mut gc, - vec![], - None, - false, - TransactionType::Undo, - ); - gc.finalize_transaction(&transaction_in_progress); - - assert_eq!(gc.undo_stack.len(), 1); - assert_eq!(gc.redo_stack.len(), 1); - assert_eq!(vec![operation_undo.clone()], gc.undo_stack[0].ops); - assert_eq!(gc.redo_stack[0].ops.len(), 0); - - // TransactionType::Redo - let transaction_in_progress = TransactionInProgress::start_transaction( - &mut gc, - vec![], - None, - false, - TransactionType::Redo, - ); - gc.finalize_transaction(&transaction_in_progress); - - assert_eq!(gc.undo_stack.len(), 2); - assert_eq!(gc.redo_stack.len(), 1); - assert_eq!(vec![operation_undo.clone()], gc.undo_stack[0].ops); - assert_eq!(gc.redo_stack[0].ops.len(), 0); - } - - #[test] - fn test_transactions_undo_redo() { - let mut gc = GridController::new(); - let (operation, operation_undo) = get_operations(&mut gc); - - assert!(!gc.has_undo()); - assert!(!gc.has_redo()); - - gc.set_in_progress_transaction( - vec![operation.clone()], - None, - false, - TransactionType::Normal, - ); - assert!(gc.has_undo()); - assert!(!gc.has_redo()); - assert_eq!(vec![operation_undo.clone()], gc.undo_stack[0].ops); - - // undo - gc.undo(None); - assert!(!gc.has_undo()); - assert!(gc.has_redo()); - - // redo - gc.redo(None); - assert!(gc.has_undo()); - assert!(!gc.has_redo()); - } - - #[test] - fn test_transactions_transaction_summary() { - let mut gc = GridController::new(); - let summary = gc.transaction_summary(); - - assert!(summary.is_none()); - } - - #[test] - fn test_transactions_updated_bounds_in_transaction() { - let mut gc = GridController::new(); - let (operation, _) = get_operations(&mut gc); - - assert_eq!(gc.grid().sheets()[0].bounds(true), GridBounds::Empty); - - gc.set_in_progress_transaction(vec![operation], None, true, TransactionType::Normal); - gc.updated_bounds_in_transaction(); - - let expected = GridBounds::NonEmpty(Rect::single_pos((0, 0).into())); - assert_eq!(gc.grid().sheets()[0].bounds(true), expected); - } - - #[test] - fn test_transactions_cell_hash() { - let hash = "test".to_string(); - let cell_hash = CellHash(hash.clone()); - assert_eq!(cell_hash.get(), hash); - - let pos = Pos::from((0, 0)); - let cell_hash = CellHash::from(pos); - assert_eq!(cell_hash, CellHash("0,0".into())); - } -} diff --git a/quadratic-core/src/controller/update_code_cell_value.rs b/quadratic-core/src/controller/update_code_cell_value.rs index c818324f17..c3bff41e30 100644 --- a/quadratic-core/src/controller/update_code_cell_value.rs +++ b/quadratic-core/src/controller/update_code_cell_value.rs @@ -1,39 +1,35 @@ use std::ops::Range; -use indexmap::IndexSet; - use crate::{ controller::{ - operation::Operation, - transaction_summary::{CellSheetsModified, TransactionSummary}, - GridController, + operations::operation::Operation, transaction_summary::CellSheetsModified, GridController, }, - grid::{CellRef, CodeCellValue, SheetId}, - Pos, Rect, Value, + grid::CodeCellValue, + Pos, Rect, SheetPos, SheetRect, Value, }; -/// updates code cell value -/// returns true if the code cell was successful -pub fn update_code_cell_value( - grid_controller: &mut GridController, - cell_ref: CellRef, - updated_code_cell_value: Option, - cells_to_compute: &mut IndexSet, - reverse_operations: &mut Vec, - summary: &mut TransactionSummary, -) -> bool { - let mut success = false; - summary.save = true; - let sheet_id = cell_ref.sheet; - let sheet = grid_controller.grid.sheet_mut_from_id(sheet_id); - if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { +impl GridController { + /// updates code cell value + /// returns true if the code cell was successful + pub fn update_code_cell_value( + &mut self, + sheet_pos: SheetPos, + updated_code_cell_value: Option, + ) -> bool { + assert!(self.transaction_in_progress); + let mut success = false; + self.summary.save = true; + let sheet_id = sheet_pos.sheet_id; + let sheet = self.grid.sheet_mut_from_id(sheet_id); + + let pos = sheet_pos.into(); let old_code_cell_value = sheet.get_code_cell(pos); if old_code_cell_value.is_some_and(|code_cell_value| { code_cell_value .get_output_value(0, 0) .is_some_and(|cell_value| cell_value.is_html()) }) { - summary.html.insert(sheet.id); + self.summary.html.insert(sheet.id); } let mut spill = false; if let Some(updated_code_cell_value) = updated_code_cell_value.clone() { @@ -43,38 +39,31 @@ pub fn update_code_cell_value( success = true; match output_value { Value::Array(array) => { - if sheet - .is_ok_to_spill_in(cell_ref, array.size()) - .unwrap_or(false) - { - summary.cell_sheets_modified.insert(CellSheetsModified::new( - sheet.id, - Pos { x: pos.x, y: pos.y }, - )); + if sheet.is_ok_to_spill_in(pos, array.size()) { + self.summary.cell_sheets_modified.insert( + CellSheetsModified::new(SheetPos { + sheet_id: sheet.id, + x: pos.x, + y: pos.y, + }), + ); spill = true; } else { spill = false; for x in 0..array.width() { - let column_id = - sheet.get_or_create_column(pos.x + x as i64).0.id; for y in 0..array.height() { - summary.cell_sheets_modified.insert( - CellSheetsModified::new( - sheet.id, - Pos { - x: pos.x, - y: pos.y + y as i64, - }, - ), + self.summary.cell_sheets_modified.insert( + CellSheetsModified::new(SheetPos { + sheet_id, + x: pos.x, + y: pos.y + y as i64, + }), ); - let row_id = - sheet.get_or_create_row(pos.y + y as i64).id; - // add all but the first cell to the compute cycle if x != 0 || y != 0 { - cells_to_compute.insert(CellRef { - sheet: sheet.id, - column: column_id, - row: row_id, + self.cells_to_compute.insert(SheetPos { + x: pos.x + x as i64, + y: pos.y + y as i64, + sheet_id, }); } } @@ -83,19 +72,19 @@ pub fn update_code_cell_value( } Value::Single(value) => { spill = false; - summary + self.summary .cell_sheets_modified - .insert(CellSheetsModified::new(sheet.id, pos)); + .insert(CellSheetsModified::new(sheet_pos)); if value.is_html() { - summary.html.insert(sheet.id); + self.summary.html.insert(sheet.id); } } }; } None => { - summary + self.summary .cell_sheets_modified - .insert(CellSheetsModified::new(sheet.id, pos)); + .insert(CellSheetsModified::new(sheet_pos)); } }; } @@ -118,203 +107,187 @@ pub fn update_code_cell_value( let old_code_cell_value = sheet.set_code_cell_value(pos, updated_code_cell_value.clone()); // updates summary.thumbnail_dirty flag - let sheet = grid_controller.grid.sheet_from_id(cell_ref.sheet); - if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { - if let Some(updated_code_cell_value) = updated_code_cell_value.as_ref() { - if let Some(output) = updated_code_cell_value.output.as_ref() { - match output.result.output_value() { - Some(output_value) => { - match output_value { - Value::Array(array) => { - summary.generate_thumbnail = summary.generate_thumbnail - || grid_controller.thumbnail_dirty_rect( - cell_ref.sheet, - Rect::new_span( - Pos { x: pos.x, y: pos.y }, - Pos { - x: pos.x + array.width() as i64, - y: pos.y + array.height() as i64, - }, - ), - ); - } - Value::Single(_) => { - summary.generate_thumbnail = summary.generate_thumbnail - || grid_controller.thumbnail_dirty_pos(sheet.id, pos); - } - }; - } - None => { - summary.generate_thumbnail = summary.generate_thumbnail - || grid_controller.thumbnail_dirty_pos(sheet.id, pos); - } + if let Some(updated_code_cell_value) = updated_code_cell_value.as_ref() { + if let Some(output) = updated_code_cell_value.output.as_ref() { + match output.result.output_value() { + Some(output_value) => { + match output_value { + Value::Array(array) => { + self.summary.generate_thumbnail = self.summary.generate_thumbnail + || self.thumbnail_dirty_sheet_rect(SheetRect::new_pos_span( + pos, + Pos { + x: pos.x + array.width() as i64, + y: pos.y + array.height() as i64, + }, + sheet_id, + )); + } + Value::Single(_) => { + self.summary.generate_thumbnail = self.summary.generate_thumbnail + || self.thumbnail_dirty_sheet_pos(sheet_pos); + } + }; + } + None => { + self.summary.generate_thumbnail = self.summary.generate_thumbnail + || self.thumbnail_dirty_sheet_pos(sheet_pos); } } } } - fetch_code_cell_difference( - grid_controller, - sheet_id, - pos, + self.fetch_code_cell_difference( + sheet_pos, old_code_cell_value.clone(), - updated_code_cell_value, - summary, - cells_to_compute, - reverse_operations, + updated_code_cell_value.clone(), ); - reverse_operations.push(Operation::SetCellCode { - cell_ref, + self.forward_operations.push(Operation::SetCellCode { + sheet_pos, + code_cell_value: updated_code_cell_value, + }); + + self.reverse_operations.push(Operation::SetCellCode { + sheet_pos, code_cell_value: old_code_cell_value, }); - summary.code_cells_modified.insert(sheet_id); + self.summary.code_cells_modified.insert(sheet_id); + + self.check_spill(sheet_pos); - grid_controller.check_spill(cell_ref, cells_to_compute, summary, reverse_operations); + success } - success -} + /// Fetches the difference between the old and new code cell values and updates the UI + #[allow(clippy::too_many_arguments)] + pub fn fetch_code_cell_difference( + &mut self, + sheet_pos: SheetPos, + old_code_cell_value: Option, + new_code_cell_value: Option, + ) { + assert!(self.transaction_in_progress); + let sheet_id = sheet_pos.sheet_id; + let sheet = self.grid.sheet_mut_from_id(sheet_id); + let mut possible_spills = vec![]; + + let (old_w, old_h) = old_code_cell_value.map_or((1, 1), |code_cell_value| { + if code_cell_value.is_html() { + self.summary.html.insert(sheet_id); + } + if code_cell_value.has_spill_error() { + (1, 1) + } else { + code_cell_value.output_size().into() + } + }); -/// Fetches the difference between the old and new code cell values and updates the UI -#[allow(clippy::too_many_arguments)] -pub fn fetch_code_cell_difference( - grid_controller: &mut GridController, - sheet_id: SheetId, - pos: Pos, - old_code_cell_value: Option, - new_code_cell_value: Option, - summary: &mut TransactionSummary, - cells_to_compute: &mut IndexSet, - reverse_operations: &mut Vec, -) { - let sheet = grid_controller.grid.sheet_mut_from_id(sheet_id); - let mut possible_spills = vec![]; - let cell_ref = sheet.get_or_create_cell_ref(pos); - - let (old_w, old_h) = old_code_cell_value.map_or((1, 1), |code_cell_value| { - if code_cell_value.is_html() { - summary.html.insert(sheet_id); - } - if code_cell_value.has_spill_error() { - (1, 1) - } else { - code_cell_value.output_size().into() - } - }); + let (new_w, new_h) = new_code_cell_value.map_or((0, 0), |code_cell_value| { + if code_cell_value.is_html() { + self.summary.html.insert(sheet_id); + } + if code_cell_value.has_spill_error() { + (1, 1) + } else { + code_cell_value.output_size().into() + } + }); - let (new_w, new_h) = new_code_cell_value.map_or((0, 0), |code_cell_value| { - if code_cell_value.is_html() { - summary.html.insert(sheet_id); - } - if code_cell_value.has_spill_error() { - (1, 1) - } else { - code_cell_value.output_size().into() - } - }); - - if old_w > new_w { - for x in new_w..old_w { - let (_, column) = sheet.get_or_create_column(pos.x + x); - let column_id = column.id; - - // remove any spills created by the updated code_cell - for y in pos.y..=pos.y + old_h { - if let Some(spill) = column.spills.get(y) { - if spill == cell_ref { - column.spills.set(y, None); + if old_w > new_w { + for x in new_w..old_w { + // the columnId necessarily exists since this is just a diff operation + let column = sheet.get_or_create_column(sheet_pos.x + x); + + // remove any spills created by the updated code_cell + for y in sheet_pos.y..=sheet_pos.y + old_h { + if let Some(spill) = column.spills.get(y) { + if spill == sheet_pos.into() { + column.spills.set(y, None); + } } } - } - column.spills.remove_range(Range { - start: pos.y, - end: pos.y + new_h + 1, - }); - for y in 0..new_h { - let row_id = sheet.get_or_create_row(pos.y + y).id; - let pos = Pos { - x: pos.x + x, - y: pos.y + y, - }; - summary - .cell_sheets_modified - .insert(CellSheetsModified::new(sheet_id, pos)); - let cell_ref_entry = CellRef { - sheet: sheet_id, - column: column_id, - row: row_id, - }; - cells_to_compute.insert(cell_ref_entry); - if y <= old_h { - possible_spills.push(cell_ref_entry); + column.spills.remove_range(Range { + start: sheet_pos.y, + end: sheet_pos.y + new_h + 1, + }); + for y in 0..new_h { + let sheet_pos_entry = SheetPos { + sheet_id, + x, + y: sheet_pos.y + y, + }; + self.cells_to_compute.insert(sheet_pos_entry); + if y <= old_h { + possible_spills.push(sheet_pos_entry); + } } } } - } - if old_h > new_h { - for x in 0..old_w { - let (_, column) = sheet.get_or_create_column(pos.x + x); - let column_id = column.id; + if old_h > new_h { + for x in 0..old_w { + // the columnId necessarily exists since this is just a diff operation + let column = sheet.get_or_create_column(sheet_pos.x + x); - // remove any spills created by the updated code_cell - for y in pos.y + new_h..=pos.y + old_h { - if let Some(spill) = column.spills.get(y) { - if spill == cell_ref { - column.spills.set(y, None); + // remove any spills created by the updated code_cell + for y in sheet_pos.y + new_h..=sheet_pos.y + old_h { + if let Some(spill) = column.spills.get(y) { + if spill == sheet_pos.into() { + column.spills.set(y, None); + } } } - } - for y in new_h..old_h { - let row_id = sheet.get_or_create_row(pos.y + y).id; - let pos = Pos { - x: pos.x + x, - y: pos.y + y, - }; - summary - .cell_sheets_modified - .insert(CellSheetsModified::new(sheet_id, pos)); - let cell_ref = CellRef { - sheet: sheet_id, - column: column_id, - row: row_id, - }; - cells_to_compute.insert(cell_ref); - possible_spills.push(cell_ref); + for y in new_h..old_h { + // the rowId necessarily exists since this is just a diff operation + let sheet_pos_entry = SheetPos { + sheet_id, + x, + y: sheet_pos.y + y, + }; + self.cells_to_compute.insert(sheet_pos_entry); + possible_spills.push(sheet_pos_entry); + } } } - } - // check for released spills - possible_spills.iter().for_each(|cell_ref| { - grid_controller.update_code_cell_value_if_spill_error_released( - *cell_ref, - cells_to_compute, - summary, - reverse_operations, + let rect = Rect::new_span( + sheet_pos.into(), + Pos { + x: sheet_pos.x + new_w.max(old_w), + y: sheet_pos.y + new_h.max(old_h), + }, ); - }); + rect.iter().for_each(|pos| { + self.summary + .cell_sheets_modified + .insert(CellSheetsModified::new(pos.to_sheet_pos(sheet_id))); + }); + + self.summary + .cell_sheets_modified + .insert(CellSheetsModified::new(sheet_pos)); + + // check for released spills + possible_spills.iter().for_each(|cell_ref| { + self.update_code_cell_value_if_spill_error_released(*cell_ref); + }); + } } #[cfg(test)] mod test { - use indexmap::IndexSet; + use std::collections::HashSet; use crate::{ - controller::{ - transaction_summary::TransactionSummary, - update_code_cell_value::fetch_code_cell_difference, GridController, - }, + controller::GridController, grid::{CodeCellLanguage, CodeCellRunOutput, CodeCellValue}, Array, ArraySize, CellValue, Pos, SheetPos, Value, }; - use super::update_code_cell_value; - #[test] fn test_fetch_code_cell_difference() { let mut gc = GridController::new(); @@ -333,7 +306,7 @@ mod test { output_value: Value::Array(Array::new_empty( ArraySize::try_from((2, 3)).expect("failed to create array"), )), - cells_accessed: Vec::new(), + cells_accessed: HashSet::new(), }, spill: false, }), @@ -350,7 +323,7 @@ mod test { output_value: Value::Array(Array::new_empty( ArraySize::try_from((1, 2)).expect("failed to create array"), )), - cells_accessed: Vec::new(), + cells_accessed: HashSet::new(), }, spill: false, }), @@ -362,23 +335,11 @@ mod test { sheet_id: sheet.id, }; - let mut summary = TransactionSummary::default(); + gc.transaction_in_progress = true; + gc.fetch_code_cell_difference(sheet_pos, old.clone(), new_smaller); + assert_eq!(gc.summary.cell_sheets_modified.len(), 1); - let mut cells_to_compute = IndexSet::new(); - let mut reverse_operations = Vec::new(); - fetch_code_cell_difference( - &mut gc, - sheet_id, - sheet_pos.into(), - old.clone(), - new_smaller, - &mut summary, - &mut cells_to_compute, - &mut reverse_operations, - ); - assert_eq!(summary.cell_sheets_modified.len(), 1); - - summary.clear(); + gc.summary.clear(false); let new_larger = Some(CodeCellValue { language: CodeCellLanguage::Python, @@ -392,23 +353,14 @@ mod test { output_value: Value::Array(Array::new_empty( ArraySize::try_from((5, 6)).expect("failed to create array"), )), - cells_accessed: Vec::new(), + cells_accessed: HashSet::new(), }, spill: false, }), }); - super::fetch_code_cell_difference( - &mut gc, - sheet_id, - sheet_pos.into(), - old, - new_larger, - &mut summary, - &mut cells_to_compute, - &mut reverse_operations, - ); - assert_eq!(summary.cell_sheets_modified.len(), 0); + gc.fetch_code_cell_difference(sheet_pos, old, new_larger); + assert_eq!(gc.summary.cell_sheets_modified.len(), 1); } #[test] @@ -416,7 +368,7 @@ mod test { let mut gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; let sheet = gc.grid.sheet_mut_from_id(sheet_id); - sheet.set_cell_value(Pos { x: 0, y: 1 }, CellValue::Text("test".into())); + let _ = sheet.set_cell_value(Pos { x: 0, y: 1 }, CellValue::Text("test".into())); let code_cell_output = Some(CodeCellValue { language: CodeCellLanguage::Python, @@ -430,22 +382,20 @@ mod test { output_value: Value::Array(Array::new_empty( ArraySize::try_from((2, 3)).expect("failed to create array"), )), - cells_accessed: Vec::new(), + cells_accessed: HashSet::new(), }, spill: false, }), }); - let sheet = gc.grid.sheet_mut_from_id(sheet_id); - let cell_ref = sheet.get_or_create_cell_ref(Pos { x: 0, y: 0 }); - - update_code_cell_value( - &mut gc, - cell_ref, + gc.transaction_in_progress = true; + gc.update_code_cell_value( + SheetPos { + x: 0, + y: 0, + sheet_id, + }, code_cell_output.clone(), - &mut IndexSet::default(), - &mut vec![], - &mut TransactionSummary::default(), ); let sheet = gc.grid.sheet_from_id(sheet_id); @@ -470,23 +420,19 @@ mod test { output_value: Value::Array(Array::new_empty( ArraySize::try_from((2, 3)).expect("failed to create array"), )), - cells_accessed: Vec::new(), + cells_accessed: HashSet::new(), }, spill: false, }), }); - let sheet = gc.grid.sheet_mut_from_id(sheet_id); - let original_cell_ref = sheet.get_or_create_cell_ref(Pos { x: 0, y: 1 }); - - update_code_cell_value( - &mut gc, - original_cell_ref, - code_cell_output.clone(), - &mut IndexSet::default(), - &mut vec![], - &mut TransactionSummary::default(), - ); + let original = SheetPos { + x: 0, + y: 1, + sheet_id, + }; + gc.transaction_in_progress = true; + gc.update_code_cell_value(original, code_cell_output.clone()); let code_cell_output = Some(CodeCellValue { language: CodeCellLanguage::Python, @@ -500,31 +446,30 @@ mod test { output_value: Value::Array(Array::new_empty( ArraySize::try_from((1, 3)).expect("failed to create array"), )), - cells_accessed: Vec::new(), + cells_accessed: HashSet::new(), }, spill: false, }), }); - let sheet = gc.grid.sheet_mut_from_id(sheet_id); - let cell_ref = sheet.get_or_create_cell_ref(Pos { x: 0, y: 0 }); + let sheet_pos = SheetPos { + x: 0, + y: 0, + sheet_id, + }; - update_code_cell_value( - &mut gc, - cell_ref, - code_cell_output.clone(), - &mut IndexSet::default(), - &mut vec![], - &mut TransactionSummary::default(), - ); + gc.update_code_cell_value(sheet_pos, code_cell_output.clone()); let sheet = gc.grid.sheet_from_id(sheet_id); let code_cell = sheet.get_code_cell(Pos { x: 0, y: 0 }); assert!(code_cell.unwrap().has_spill_error()); - assert_eq!(sheet.get_column(0).unwrap().spills.get(0), Some(cell_ref)); + assert_eq!( + sheet.get_column(0).unwrap().spills.get(0), + Some(sheet_pos.into()) + ); assert_eq!( sheet.get_column(0).unwrap().spills.get(1), - Some(original_cell_ref) + Some(original.into()) ); } } diff --git a/quadratic-core/src/controller/auto_complete.rs b/quadratic-core/src/controller/user_actions/auto_complete.rs similarity index 51% rename from quadratic-core/src/controller/auto_complete.rs rename to quadratic-core/src/controller/user_actions/auto_complete.rs index 90ac174250..b119f03b04 100644 --- a/quadratic-core/src/controller/auto_complete.rs +++ b/quadratic-core/src/controller/user_actions/auto_complete.rs @@ -1,26 +1,6 @@ -use anyhow::{anyhow, Result}; -use itertools::Itertools; - -use super::{ - formatting::CellFmtArray, operation::Operation, transaction_summary::TransactionSummary, - transactions::TransactionType, GridController, -}; -use crate::{ - grid::{ - series::{find_auto_complete, SeriesOptions}, - RegionRef, Sheet, SheetId, - }, - util::maybe_reverse_range, - Array, CellValue, Pos, Rect, -}; - -#[derive(PartialEq)] -pub enum ExpandDirection { - Up, - Down, - Left, - Right, -} +use crate::controller::{transaction_summary::TransactionSummary, GridController}; +use crate::{controller::execution::TransactionType, grid::SheetId, Rect}; +use anyhow::Result; impl GridController { /// Extend and/or shrink the contents of selection to range by inferring patterns. @@ -33,604 +13,13 @@ impl GridController { pub fn autocomplete( &mut self, sheet_id: SheetId, - mut selection: Rect, + selection: Rect, range: Rect, cursor: Option, ) -> Result { - let mut operations = vec![]; - let mut initial_down_range: Option = None; - let mut initial_up_range: Option = None; - - let should_expand_up = range.min.y < selection.min.y; - let should_expand_down = range.max.y > selection.max.y; - let should_expand_left = range.min.x < selection.min.x; - let should_expand_right = range.max.x > selection.max.x; - - let should_shrink_width = range.max.x < selection.max.x; - let should_shrink_height = range.max.y < selection.max.y; - - // shrink width, from right to left - if should_shrink_width { - let delete_range = Rect::new_span( - (range.max.x + 1, range.min.y).into(), - (selection.max.x, selection.max.y).into(), - ); - let ops = self.shrink(sheet_id, delete_range); - operations.extend(ops); - selection.max.x = range.max.x; - } - - // shrink height, from bottom to top - if should_shrink_height { - let delete_range = Rect::new_span( - (selection.min.x, range.max.y + 1).into(), - (range.max.x, selection.max.y).into(), - ); - let ops = self.shrink(sheet_id, delete_range); - operations.extend(ops); - selection.max.y = range.max.y; - } - - // expand up - if should_expand_up { - let new_range = Rect::new_span( - (selection.min.x, selection.min.y - 1).into(), - (selection.max.x, range.min.y).into(), - ); - let ops = self.expand_up(sheet_id, &selection, &new_range)?; - operations.extend(ops); - initial_up_range = Some(range); - } - - // expand down - if should_expand_down { - let new_range = Rect::new_span( - (selection.min.x, selection.max.y + 1).into(), - (selection.max.x, range.max.y).into(), - ); - let ops = self.expand_down(sheet_id, &selection, &new_range)?; - operations.extend(ops); - initial_down_range = Some(range); - } - // expand left - if should_expand_left { - let new_range = Rect::new_span( - (range.min.x, selection.min.y).into(), - (selection.min.x - 1, selection.max.y).into(), - ); - - let down_range = initial_down_range.map(|initial_down_range| { - Rect::new_span( - (initial_down_range.min.x, selection.max.y + 1).into(), - (selection.min.x - 1, initial_down_range.max.y).into(), - ) - }); - - let up_range = initial_up_range.map(|initial_up_range| { - Rect::new_span( - initial_up_range.min, - (selection.min.x - 1, selection.min.y - 1).into(), - ) - }); - - let ops = self.expand_left(sheet_id, &selection, &new_range, down_range, up_range)?; - operations.extend(ops); - } - - // expand right - if should_expand_right { - let new_range = Rect::new_span( - (selection.max.x + 1, selection.max.y).into(), - (range.max.x, selection.max.y).into(), - ); - - let down_range = initial_down_range.map(|initial_down_range| { - Rect::new_span( - (selection.max.x + 1, selection.max.y + 1).into(), - initial_down_range.max, - ) - }); - - let up_range = initial_up_range.map(|initial_up_range| { - Rect::new_span( - (selection.max.x + 1, initial_up_range.min.y).into(), - (initial_up_range.max.x, selection.min.y - 1).into(), - ) - }); - - let ops = self.expand_right(sheet_id, &selection, &new_range, down_range, up_range)?; - operations.extend(ops); - } - - Ok(self.set_in_progress_transaction(operations, cursor, true, TransactionType::Normal)) - } - - /// Delete cell values and formats in a given range. - fn shrink(&mut self, sheet_id: SheetId, delete_range: Rect) -> Vec { - let mut ops = vec![]; - - ops.extend(self.delete_cells_rect_operations(sheet_id, delete_range)); - ops.extend(self.clear_formatting_operations(sheet_id, delete_range)); - ops - } - - fn expand_right( - &mut self, - sheet_id: SheetId, - selection: &Rect, - range: &Rect, - down_range: Option, - up_range: Option, - ) -> Result> { - let mut format_ops = vec![]; - let mut values = vec![]; - let mut formats = vec![]; - let mut ops = selection - .y_range() - .map(|y| { - let source_row = - Rect::new_span((selection.min.x, y).into(), (selection.max.x, y).into()); - let target_row = Rect::new_span((range.min.x, y).into(), (range.max.x, y).into()); - let format = self.get_all_cell_formats(sheet_id, source_row); - let width = selection.width() as usize; - - // for each column, apply the formats to a block (selection.width, y) of new cells - range.x_range().step_by(width).for_each(|x| { - let new_x = range.max.x.min(x + width as i64 - 1); - let format_rect = Rect::new_span((x, y).into(), (new_x, y).into()); - format_ops.extend(apply_formats(self.region(sheet_id, format_rect), &format)); - }); - - formats.push(format); - let (operations, cell_values) = - self.apply_auto_complete(sheet_id, false, &source_row, &target_row, None)?; - values.extend(cell_values); - - Ok(operations) - }) - .flatten_ok() - .collect::>>()?; - - if let Some(down_range) = down_range { - ops.extend(self.expand_up_or_down_from_right( - sheet_id, - selection, - &down_range, - &values, - range.width() as i64, - ExpandDirection::Down, - )?); - } - - if let Some(up_range) = up_range { - ops.extend(self.expand_up_or_down_from_right( - sheet_id, - selection, - &up_range, - &values, - range.width() as i64, - ExpandDirection::Up, - )?); - } - - ops.extend(format_ops); - Ok(ops) - } - - fn expand_left( - &mut self, - sheet_id: SheetId, - selection: &Rect, - range: &Rect, - down_range: Option, - up_range: Option, - ) -> Result> { - let mut format_ops = vec![]; - let mut values = vec![]; - let mut formats = vec![]; - let mut ops = selection - .y_range() - .map(|y| { - let source_row = - Rect::new_span((selection.min.x, y).into(), (selection.max.x, y).into()); - let target_row = Rect::new_span((range.min.x, y).into(), (range.max.x, y).into()); - let mut format = self.get_all_cell_formats(sheet_id, source_row); - let width = selection.width() as usize; - - // for each column, apply the formats to a block (selection.width, y) of new cells - range.x_range().rev().step_by(width).for_each(|x| { - let mut new_x = x - width as i64 + 1; - - if new_x < range.min.x { - let source_col = Rect::new_span( - (selection.min.x + range.min.x - new_x, y).into(), - (selection.max.x, y).into(), - ); - new_x = range.min.x; - format = self.get_all_cell_formats(sheet_id, source_col); - } - - let format_rect = Rect::new_span((x, y).into(), (new_x, y).into()); - format_ops.extend(apply_formats(self.region(sheet_id, format_rect), &format)); - }); - - formats.extend(format); - let (operations, cell_values) = - self.apply_auto_complete(sheet_id, true, &source_row, &target_row, None)?; - values.extend(cell_values); - - Ok(operations) - }) - .flatten_ok() - .collect::>>()?; - - if let Some(down_range) = down_range { - ops.extend(self.expand_up_or_down_from_left( - sheet_id, - selection, - &down_range, - &values, - range.width() as i64, - ExpandDirection::Down, - )?); - } - - if let Some(up_range) = up_range { - ops.extend(self.expand_up_or_down_from_left( - sheet_id, - selection, - &up_range, - &values, - range.width() as i64, - ExpandDirection::Up, - )?); - } - - ops.extend(format_ops); - Ok(ops) + let ops = self.autocomplete_operations(sheet_id, selection, range)?; + Ok(self.set_in_progress_transaction(ops, cursor, true, TransactionType::User)) } - - fn expand_down( - &mut self, - sheet_id: SheetId, - selection: &Rect, - range: &Rect, - ) -> Result> { - let mut format_ops = vec![]; - let mut values = vec![]; - let mut formats = vec![]; - let mut ops = selection - .x_range() - .rev() - .map(|x| { - let source_col = - Rect::new_span((x, selection.min.y).into(), (x, selection.max.y).into()); - let target_col = - Rect::new_span((x, selection.max.y + 1).into(), (x, range.max.y).into()); - let format = self.get_all_cell_formats(sheet_id, source_col); - let height = selection.height() as usize; - - // for each row, apply the formats to a block (x, selection.height) of new cells - range.y_range().step_by(height).for_each(|y| { - let new_y = range.max.y.min(y + height as i64 - 1); - let format_rect = Rect::new_span((x, y).into(), (x, new_y).into()); - format_ops.extend(apply_formats(self.region(sheet_id, format_rect), &format)); - }); - - formats.extend(format); - let (operations, cell_values) = - self.apply_auto_complete(sheet_id, false, &source_col, &target_col, None)?; - values.extend(cell_values); - - Ok(operations) - }) - .flatten_ok() - .collect::>>()?; - - ops.extend(format_ops); - Ok(ops) - } - - fn expand_up( - &mut self, - sheet_id: SheetId, - selection: &Rect, - range: &Rect, - ) -> Result> { - let mut format_ops = vec![]; - let mut values = vec![]; - let mut formats = vec![]; - let mut ops = selection - .x_range() - .map(|x| { - let source_col = - Rect::new_span((x, selection.min.y).into(), (x, selection.max.y).into()); - let target_col = - Rect::new_span((x, selection.min.y - 1).into(), (x, range.min.y).into()); - let mut format = self.get_all_cell_formats(sheet_id, source_col); - let height = selection.height() as usize; - - // for each row, apply the formats to a block (x, selection.height) of new cells - range.y_range().rev().step_by(height).for_each(|y| { - let mut new_y = y - height as i64 + 1; - - // since the new_y is less than the range min, we need to - // adjust the format since this is ine reverse order - if new_y < range.min.y { - let source_col = Rect::new_span( - (x, selection.min.y + range.min.y - new_y).into(), - (x, selection.max.y).into(), - ); - new_y = range.min.y; - format = self.get_all_cell_formats(sheet_id, source_col); - } - - let format_rect = Rect::new_span((x, y).into(), (x, new_y).into()); - format_ops.extend(apply_formats(self.region(sheet_id, format_rect), &format)); - }); - - formats.extend(format); - let (operations, cell_values) = - self.apply_auto_complete(sheet_id, true, &source_col, &target_col, None)?; - values.extend(cell_values); - - Ok(operations) - }) - .flatten_ok() - .collect::>>()?; - - ops.extend(format_ops); - Ok(ops) - } - - fn expand_up_or_down_from_right( - &mut self, - sheet_id: SheetId, - selection: &Rect, - range: &Rect, - values: &Vec, - width: i64, - direction: ExpandDirection, - ) -> Result> { - let mut format_ops = vec![]; - let height = values.len() as i64 / width; - - let mut ops = range - .x_range() - .enumerate() - .map(|(index, x)| { - let target_col = Rect::new_span((x, range.min.y).into(), (x, range.max.y).into()); - - let vals = (0..height) - .map(|i| { - let array_index = (index as i64 + (i * width)) as usize; - values - .get(array_index) - .unwrap_or(&CellValue::Blank) - .to_owned() - }) - .collect::>(); - - let format_x = selection.min.x + (x - selection.min.x) % selection.width() as i64; - let format_source_rect = Rect::new_span( - (format_x, selection.min.y).into(), - (format_x, selection.max.y).into(), - ); - let mut format = self.get_all_cell_formats(sheet_id, format_source_rect); - - maybe_reverse_range(range.y_range(), direction == ExpandDirection::Up) - .step_by(height as usize) - .for_each(|y| { - let new_y = if direction == ExpandDirection::Down { - range.max.y.min(y + height - 1) - } else { - // since the new_y is less than the range min, we need to - // adjust the format since this is ine reverse order - let calc_y = y - height + 1; - if calc_y < range.min.y { - let format_source_rect = Rect::new_span( - (format_x, selection.min.y + range.min.y - calc_y).into(), - (format_x, selection.max.y).into(), - ); - format = self.get_all_cell_formats(sheet_id, format_source_rect); - range.min.y - } else { - y - height + 1 - } - }; - let format_rect = Rect::new_span((x, y).into(), (x, new_y).into()); - format_ops - .extend(apply_formats(self.region(sheet_id, format_rect), &format)); - }); - - let (operations, _) = self.apply_auto_complete( - sheet_id, - direction == ExpandDirection::Up, - &target_col, - &target_col, - Some(vals), - )?; - - Ok(operations) - }) - .flatten_ok() - .collect::>>()?; - - ops.extend(format_ops); - - Ok(ops) - } - - fn expand_up_or_down_from_left( - &mut self, - sheet_id: SheetId, - selection: &Rect, - range: &Rect, - values: &Vec, - width: i64, - direction: ExpandDirection, - ) -> Result> { - let mut format_ops = vec![]; - let height = values.len() as i64 / width; - - let mut ops = range - .x_range() - .rev() - .enumerate() - .map(|(index, x)| { - let target_col = if direction == ExpandDirection::Down { - Rect::new_span((x, range.min.y).into(), (x, range.max.y).into()) - } else { - Rect::new_span((x, selection.min.y - 1).into(), (x, range.min.y).into()) - }; - - let vals = (0..height) - .map(|i| { - let array_index = (i * width) + width - index as i64 - 1; - values - .get(array_index as usize) - .unwrap_or(&CellValue::Blank) - .to_owned() - }) - .collect::>(); - - let format_x = selection.max.x - (index as i64 % selection.width() as i64); - let format_source_rect = Rect::new_span( - (format_x, selection.min.y).into(), - (format_x, selection.max.y).into(), - ); - let mut format = self.get_all_cell_formats(sheet_id, format_source_rect); - - maybe_reverse_range(range.y_range(), direction == ExpandDirection::Up) - .step_by(height as usize) - .for_each(|y| { - let new_y = if direction == ExpandDirection::Down { - range.max.y.min(y + height - 1) - } else { - // since the new_y is less than the range min, we need to - // adjust the format since this is ine reverse order - let calc_y = y - height + 1; - if calc_y < range.min.y { - let format_source_rect = Rect::new_span( - (format_x, selection.min.y + range.min.y - calc_y).into(), - (format_x, selection.max.y).into(), - ); - format = self.get_all_cell_formats(sheet_id, format_source_rect); - range.min.y - } else { - y - height + 1 - } - }; - - let format_rect = Rect::new_span((x, y).into(), (x, new_y).into()); - format_ops - .extend(apply_formats(self.region(sheet_id, format_rect), &format)); - }); - - let (operations, _) = self.apply_auto_complete( - sheet_id, - direction == ExpandDirection::Up, - &target_col, - &target_col, - Some(vals), - )?; - - Ok(operations) - }) - .flatten_ok() - .collect::>>()?; - - ops.extend(format_ops); - - Ok(ops) - } - - /// Gven an array of values, determine if a series exists and if so, apply it. - fn apply_auto_complete( - &mut self, - sheet_id: SheetId, - negative: bool, - selection: &Rect, - range: &Rect, - cell_values: Option>, - ) -> Result<(Vec, Vec)> { - let sheet = self.sheet(sheet_id); - let values = if let Some(cell_values) = cell_values { - cell_values - } else { - cell_values_in_rect(selection, sheet)? - .into_cell_values_vec() - .into_iter() - .collect::>() - }; - - let series = find_auto_complete(SeriesOptions { - series: values, - spaces: (range.width() * range.height()) as i32, - negative, - }); - - let values = Array::new_row_major(range.size(), series.to_owned().into()) - .map_err(|e| anyhow!("Could not create array of size {:?}: {:?}", range.size(), e))?; - - let start_pos = range.min; - let end_pos = Pos { - x: start_pos.x + values.width() as i64 - 1, - y: start_pos.y + values.height() as i64 - 1, - }; - let rect = Rect { - min: start_pos, - max: end_pos, - }; - let region = self.region(sheet_id, rect); - - let ops = vec![Operation::SetCellValues { region, values }]; - - Ok((ops, series)) - } -} - -/// Apply formats to a given region. -/// -/// TODO(ddimaria): this funcion is sufficiently generic that it could be moved -/// TODO(ddimaria): we could remove the clones below by modifying the Operation -/// calls to accept references since they don't mutate the region. -pub fn apply_formats(region: RegionRef, formats: &[CellFmtArray]) -> Vec { - formats - .iter() - .map(|format| Operation::SetCellFormats { - region: region.clone(), - attr: format.clone(), - }) - .collect() -} - -/// In a given rect, collect all cell values into an array. -/// -/// TODO(ddimaria): determine if this should go in the cell.rs file or equiv -/// TODO(ddimaria): is this necessary as it's more performant to just pluck the data from the sheet direclty -pub fn cell_values_in_rect(&selection: &Rect, sheet: &Sheet) -> Result { - let values = selection - .y_range() - .flat_map(|y| { - selection - .x_range() - .map(|x| { - sheet - .get_cell_value(Pos { x, y }) - .unwrap_or_else(|| CellValue::Blank) - }) - .collect::>() - }) - .collect(); - - Array::new_row_major(selection.size(), values).map_err(|e| { - anyhow!( - "Could not create array of size {:?}: {:?}", - selection.size(), - e - ) - }) } #[cfg(test)] @@ -642,6 +31,7 @@ mod tests { assert_cell_format_bold_row, assert_cell_format_cell_fill_color_row, assert_cell_value, assert_cell_value_row, print_table, }, + Pos, SheetPos, SheetRect, }; fn test_setup_rect(selection: &Rect) -> (GridController, SheetId) { @@ -680,24 +70,18 @@ mod tests { for y in selection.y_range() { for x in selection.x_range() { - let pos = Pos { x, y }; - grid_controller.set_cell_value(sheet_id, pos, vals[count].to_string(), None); + let sheet_pos = SheetPos { x, y, sheet_id }; + grid_controller.set_cell_value(sheet_pos, vals[count].to_string(), None); if let Some(is_bold) = bolds.get(count) { if *is_bold { - grid_controller.set_cell_bold( - sheet_id, - Rect::single_pos(pos), - Some(true), - None, - ); + grid_controller.set_cell_bold(sheet_pos.into(), Some(true), None); } } if let Some(fill_color) = fill_colors.get(count) { grid_controller.set_cell_fill_color( - sheet_id, - Rect::single_pos(pos), + SheetRect::single_sheet_pos(sheet_pos), Some(fill_color.to_lowercase()), None, ); @@ -715,7 +99,7 @@ mod tests { let selected: Rect = Rect::new_span(Pos { x: -1, y: 0 }, Pos { x: 2, y: 1 }); let (grid_controller, sheet_id) = test_setup_rect(&selected); let sheet = grid_controller.grid().sheet_from_id(sheet_id); - let result = cell_values_in_rect(&selected, sheet).unwrap(); + let result = sheet.cell_values_in_rect(&selected).unwrap(); let expected = array![ "a", "h", "x", "g"; "f", "z", "r", "b"; diff --git a/quadratic-core/src/controller/borders.rs b/quadratic-core/src/controller/user_actions/borders.rs similarity index 60% rename from quadratic-core/src/controller/borders.rs rename to quadratic-core/src/controller/user_actions/borders.rs index 499c954e83..62a9b02ad5 100644 --- a/quadratic-core/src/controller/borders.rs +++ b/quadratic-core/src/controller/user_actions/borders.rs @@ -1,33 +1,25 @@ -use super::operation::Operation; -use super::transactions::TransactionType; -use super::GridController; -use crate::controller::transaction_summary::TransactionSummary; -use crate::grid::generate_borders; -use crate::{ - grid::{BorderSelection, BorderStyle, SheetId}, - Rect, +use crate::controller::{ + execution::TransactionType, transaction_summary::TransactionSummary, GridController, }; +use crate::grid::{BorderSelection, BorderStyle}; +use crate::SheetRect; impl GridController { pub async fn set_borders( &mut self, - sheet_id: SheetId, - rect: Rect, + sheet_rect: SheetRect, selections: Vec, style: Option, cursor: Option, ) -> TransactionSummary { - let region = self.region(sheet_id, rect); - let sheet = self.sheet(sheet_id); - let borders = generate_borders(sheet, ®ion, selections, style); - let ops = vec![Operation::SetBorders { region, borders }]; - self.set_in_progress_transaction(ops, cursor, false, TransactionType::Normal) + let ops = self.set_borders_operations(sheet_rect, selections, style); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) } } #[cfg(test)] mod tests { - use crate::{color::Rgba, grid::CellBorderLine}; + use crate::{color::Rgba, grid::CellBorderLine, Pos}; use super::*; @@ -35,14 +27,14 @@ mod tests { fn test_set_borders() { let mut grid_controller = GridController::new(); let sheet_id = grid_controller.grid.sheets()[0].id; - let rect = Rect::single_pos((0, 0).into()); + let sheet_rect = SheetRect::single_pos(Pos { x: 0, y: 0 }, sheet_id); let selections = vec![BorderSelection::Top, BorderSelection::Left]; let style = Some(BorderStyle { color: Rgba::default(), line: CellBorderLine::Line1, }); - tokio_test::block_on(grid_controller.set_borders(sheet_id, rect, selections, style, None)); + tokio_test::block_on(grid_controller.set_borders(sheet_rect, selections, style, None)); let borders = grid_controller.grid.sheets()[0] .borders() diff --git a/quadratic-core/src/controller/user_actions/cells.rs b/quadratic-core/src/controller/user_actions/cells.rs new file mode 100644 index 0000000000..2a0d6c2700 --- /dev/null +++ b/quadratic-core/src/controller/user_actions/cells.rs @@ -0,0 +1,206 @@ +use crate::controller::{ + execution::TransactionType, transaction_summary::TransactionSummary, GridController, +}; + +use crate::{ + grid::{CodeCellLanguage, SheetId}, + Rect, SheetPos, SheetRect, +}; + +impl GridController { + pub fn populate_with_random_floats(&mut self, sheet_id: SheetId, region: &Rect) { + let sheet = self.grid.sheet_mut_from_id(sheet_id); + sheet.with_random_floats(region); + } + + /// sets the value based on a user's input and converts input to proper NumericFormat + pub fn set_cell_value( + &mut self, + sheet_pos: SheetPos, + value: String, + cursor: Option, + ) -> TransactionSummary { + let ops = self.set_cell_value_operations(sheet_pos, value); + self.set_in_progress_transaction(ops, cursor, true, TransactionType::User) + } + + pub fn set_cell_code( + &mut self, + sheet_pos: SheetPos, + language: CodeCellLanguage, + code_string: String, + cursor: Option, + ) -> TransactionSummary { + let ops = self.set_cell_code_operations(sheet_pos, language, code_string); + self.set_in_progress_transaction(ops, cursor, true, TransactionType::User) + } + + /// Deletes the cell values and code in a given region. + /// Creates and runs a transaction, also updates dependent cells. + /// Returns a [`TransactionSummary`]. + pub fn delete_cells_rect( + &mut self, + sheet_rect: SheetRect, + cursor: Option, + ) -> TransactionSummary { + let ops = self.delete_cells_rect_operations(sheet_rect); + self.set_in_progress_transaction(ops, cursor, true, TransactionType::User) + } + + pub fn clear_formatting( + &mut self, + sheet_rect: SheetRect, + cursor: Option, + ) -> TransactionSummary { + let ops = self.clear_formatting_operations(sheet_rect); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) + } + + pub fn delete_values_and_formatting( + &mut self, + sheet_rect: SheetRect, + cursor: Option, + ) -> TransactionSummary { + let ops = self.delete_values_and_formatting_operations(sheet_rect); + self.set_in_progress_transaction(ops, cursor, true, TransactionType::User) + } +} + +#[cfg(test)] +mod test { + use crate::{ + controller::{transaction_summary::CellSheetsModified, GridController}, + grid::{NumericDecimals, NumericFormat}, + CellValue, SheetPos, + }; + use std::{collections::HashSet, str::FromStr}; + + use bigdecimal::BigDecimal; + + #[test] + fn test_set_cell_value_undo_redo() { + let mut g = GridController::new(); + let sheet_id = g.grid.sheets()[0].id; + let sheet_pos = SheetPos { + x: 3, + y: 6, + sheet_id, + }; + let get_the_cell = |g: &GridController| { + g.sheet(sheet_id) + .get_cell_value(sheet_pos.into()) + .unwrap_or_default() + }; + let mut cell_sheets_modified = HashSet::new(); + cell_sheets_modified.insert(CellSheetsModified::new(sheet_pos)); + assert_eq!(get_the_cell(&g), CellValue::Blank); + g.set_cell_value(sheet_pos, String::from("a"), None); + assert_eq!(get_the_cell(&g), CellValue::Text(String::from("a"))); + g.set_cell_value(sheet_pos, String::from("b"), None); + assert_eq!(get_the_cell(&g), CellValue::Text(String::from("b"))); + assert_eq!(g.undo(None).cell_sheets_modified, cell_sheets_modified); + assert_eq!(get_the_cell(&g), CellValue::Text(String::from("a"))); + assert_eq!(g.redo(None).cell_sheets_modified, cell_sheets_modified); + assert_eq!(get_the_cell(&g), CellValue::Text(String::from("b"))); + assert_eq!(g.undo(None).cell_sheets_modified, cell_sheets_modified); + assert_eq!(get_the_cell(&g), CellValue::Text(String::from("a"))); + assert_eq!(g.undo(None).cell_sheets_modified, cell_sheets_modified); + assert_eq!(get_the_cell(&g), CellValue::Blank); + assert_eq!(g.undo(None).cell_sheets_modified, HashSet::default()); + assert_eq!(get_the_cell(&g), CellValue::Blank); + assert_eq!(g.redo(None).cell_sheets_modified, cell_sheets_modified); + assert_eq!(get_the_cell(&g), CellValue::Text(String::from("a"))); + assert_eq!(g.redo(None).cell_sheets_modified, cell_sheets_modified); + assert_eq!(get_the_cell(&g), CellValue::Text(String::from("b"))); + assert_eq!(g.redo(None).cell_sheets_modified, HashSet::default()); + assert_eq!(get_the_cell(&g), CellValue::Text(String::from("b"))); + } + + #[test] + fn test_unpack_currency() { + let value = String::from("$123.123"); + assert_eq!( + CellValue::unpack_currency(&value), + Some((String::from("$"), BigDecimal::from_str("123.123").unwrap())) + ); + + let value = String::from("test"); + assert_eq!(CellValue::unpack_currency(&value), None); + + let value = String::from("$123$123"); + assert_eq!(CellValue::unpack_currency(&value), None); + + let value = String::from("$123.123abc"); + assert_eq!(CellValue::unpack_currency(&value), None); + } + + #[test] + fn test_set_cell_value() { + let mut gc = GridController::new(); + let sheet_id = gc.grid.sheets()[0].id; + let sheet_pos = SheetPos { + x: 0, + y: 0, + sheet_id, + }; + let get_cell_value = |g: &GridController| { + g.sheet(sheet_id) + .get_cell_value(sheet_pos.into()) + .unwrap_or_default() + }; + let get_cell_numeric_format = |g: &GridController| { + g.sheet(sheet_id) + .get_formatting_value::(sheet_pos.into()) + }; + let get_cell_numeric_decimals = |g: &GridController| { + g.sheet(sheet_id) + .get_formatting_value::(sheet_pos.into()) + }; + + // empty string converts to blank cell value + gc.set_cell_value(sheet_pos, " ".into(), None); + assert_eq!(get_cell_value(&gc), CellValue::Blank); + + // currency + gc.set_cell_value(sheet_pos, "$1.22".into(), None); + assert_eq!( + get_cell_value(&gc), + CellValue::Number(BigDecimal::from_str("1.22").unwrap()) + ); + assert_eq!( + get_cell_numeric_format(&gc), + Some(NumericFormat { + kind: crate::grid::NumericFormatKind::Currency, + symbol: Some("$".into()) + }) + ); + assert_eq!(get_cell_numeric_decimals(&gc), Some(2)); + + // number + gc.set_cell_value(sheet_pos, "1.22".into(), None); + assert_eq!( + get_cell_value(&gc), + CellValue::Number(BigDecimal::from_str("1.22").unwrap()) + ); + assert_eq!(get_cell_numeric_decimals(&gc), Some(2)); + + // percentage + gc.set_cell_value(sheet_pos, "10.55%".into(), None); + assert_eq!( + get_cell_value(&gc), + CellValue::Number(BigDecimal::from_str(".1055").unwrap()) + ); + assert_eq!( + get_cell_numeric_format(&gc), + Some(NumericFormat { + kind: crate::grid::NumericFormatKind::Percentage, + symbol: None + }) + ); + assert_eq!(get_cell_numeric_decimals(&gc), Some(2)); + + // array + gc.set_cell_value(sheet_pos, "[1,2,3]".into(), None); + assert_eq!(get_cell_value(&gc), CellValue::Text("[1,2,3]".into())); + } +} diff --git a/quadratic-core/src/controller/clipboard.rs b/quadratic-core/src/controller/user_actions/clipboard.rs similarity index 59% rename from quadratic-core/src/controller/clipboard.rs rename to quadratic-core/src/controller/user_actions/clipboard.rs index aef1a11f49..745bf7428d 100644 --- a/quadratic-core/src/controller/clipboard.rs +++ b/quadratic-core/src/controller/user_actions/clipboard.rs @@ -1,51 +1,32 @@ -use super::{ - formatting::CellFmtArray, operation::Operation, transaction_summary::TransactionSummary, - transactions::TransactionType, GridController, +use crate::controller::{ + execution::TransactionType, + operations::clipboard::{Clipboard, ClipboardCell}, + transaction_summary::TransactionSummary, + GridController, }; use crate::{ - grid::{ - generate_borders_full, get_cell_borders_in_rect, BorderSelection, CellBorders, - CodeCellValue, RegionRef, SheetId, - }, - Array, ArraySize, CellValue, Pos, Rect, + grid::{get_cell_borders_in_rect, CodeCellValue}, + Pos, SheetPos, SheetRect, }; use htmlescape; -use regex::Regex; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Serialize, Deserialize)] -pub struct ClipboardCell { - pub value: Option, - pub spill: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct Clipboard { - w: u32, - h: u32, - cells: Vec, - formats: Vec, - borders: Vec<(i64, i64, Option)>, - code: Vec<(Pos, CodeCellValue)>, -} impl GridController { - pub fn copy_to_clipboard(&self, sheet_id: SheetId, rect: Rect) -> (String, String) { + pub fn copy_to_clipboard(&self, sheet_rect: SheetRect) -> (String, String) { let mut cells = vec![]; let mut plain_text = String::new(); let mut html = String::from(""); let mut code = vec![]; - let sheet = &mut self.grid().sheet_from_id(sheet_id); + let sheet = &mut self.grid().sheet_from_id(sheet_rect.sheet_id); - for y in rect.y_range() { - if y != rect.min.y { + for y in sheet_rect.y_range() { + if y != sheet_rect.min.y { plain_text.push('\n'); html.push_str(""); } html.push_str(""); - for x in rect.x_range() { - if x != rect.min.x { + for x in sheet_rect.x_range() { + if x != sheet_rect.min.x { plain_text.push('\t'); html.push_str(""); } @@ -64,8 +45,8 @@ impl GridController { if let Some(code_cell_value) = sheet.get_code_cell(pos) { code.push(( Pos { - x: x - rect.min.x, - y: y - rect.min.y, + x: x - sheet_rect.min.x, + y: y - sheet_rect.min.y, }, CodeCellValue { language: code_cell_value.language, @@ -117,15 +98,15 @@ impl GridController { } } - let formats = self.get_all_cell_formats(sheet_id, rect); - let borders = get_cell_borders_in_rect(sheet, rect); + let formats = self.get_all_cell_formats(sheet_rect); + let borders = get_cell_borders_in_rect(sheet, sheet_rect.into()); let clipboard = Clipboard { cells, formats, borders, code, - w: rect.width(), - h: rect.height(), + w: sheet_rect.width() as u32, + h: sheet_rect.height() as u32, }; html.push_str(""); @@ -140,253 +121,37 @@ impl GridController { pub fn cut_to_clipboard( &mut self, - sheet_id: SheetId, - rect: Rect, + sheet_rect: SheetRect, cursor: Option, ) -> (TransactionSummary, String, String) { - let copy = self.copy_to_clipboard(sheet_id, rect); - let summary = self.delete_values_and_formatting(sheet_id, rect, cursor); - (summary, copy.0, copy.1) - } - - fn array_from_clipboard_cells(clipboard: Clipboard) -> Option { - if clipboard.w == 0 && clipboard.h == 0 { - return None; - } - - let mut array = Array::new_empty(ArraySize::new(clipboard.w, clipboard.h).unwrap()); - let mut x = 0; - let mut y = 0; - - clipboard.cells.iter().for_each(|cell| { - let value = cell.value.to_owned().map_or(CellValue::Blank, |v| v); - // ignore result errors - let _ = array.set(x, y, value); - - x += 1; - - if x == clipboard.w { - x = 0; - y += 1; - } - }); - - Some(array) - } - - fn set_clipboard_cells( - &mut self, - sheet_id: SheetId, - start_pos: Pos, - clipboard: Clipboard, - cursor: Option, - ) -> TransactionSummary { - let mut compute = false; - let rect = Rect { - min: start_pos, - max: Pos { - x: start_pos.x + (clipboard.w as i64) - 1, - y: start_pos.y + (clipboard.h as i64) - 1, - }, - }; - let formats = clipboard.formats.clone(); - let borders = clipboard.borders.clone(); - let code = clipboard.code.clone(); - - let mut ops = vec![]; - let region = self.region(sheet_id, rect); - let values = GridController::array_from_clipboard_cells(clipboard); - if let Some(values) = values { - ops.push(Operation::SetCellValues { - region: region.clone(), - values, - }); - compute = true; - } - - let sheet = self.grid.sheet_mut_from_id(sheet_id); - - // remove any overlapping code cells (which will automatically set the reverse operations) - region.iter().for_each(|cell_ref| { - if let Some(_code_cell) = sheet.get_code_cell_from_ref(cell_ref) { - if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { - // no need to clear code cells that are being pasted - if !code.iter().any(|(code_pos, _)| { - Pos { - x: code_pos.x + start_pos.x, - y: code_pos.y + start_pos.y, - } == pos - }) { - ops.push(Operation::SetCellCode { - cell_ref, - code_cell_value: None, - }); - compute = true; - } - } - } - }); - - // add copied code cells to the sheet - code.iter().for_each(|entry| { - let cell_ref = sheet.get_or_create_cell_ref(Pos { - x: entry.0.x + start_pos.x, - y: entry.0.y + start_pos.y, - }); - ops.push(Operation::SetCellCode { - cell_ref, - code_cell_value: Some(entry.1.clone()), - }); - compute = true; - }); - - formats.iter().for_each(|format| { - ops.push(Operation::SetCellFormats { - region: region.clone(), - attr: format.clone(), - }); - }); - - // add borders to the sheet - borders.iter().for_each(|(x, y, cell_borders)| { - if let Some(cell_borders) = cell_borders { - let mut border_selections = vec![]; - let mut border_styles = vec![]; - let (column, _) = sheet.get_or_create_column(*x + start_pos.x); - let row_id = sheet.get_or_create_row(*y + start_pos.y); - let region = RegionRef { - sheet: sheet.id, - columns: vec![column.id], - rows: vec![row_id.id], - }; - - cell_borders - .borders - .iter() - .enumerate() - .for_each(|(index, border_style)| { - if let Some(border_style) = border_style.to_owned() { - let border_selection = match index { - 0 => BorderSelection::Left, - 1 => BorderSelection::Top, - 2 => BorderSelection::Right, - 3 => BorderSelection::Bottom, - _ => BorderSelection::Clear, - }; - border_selections.push(border_selection); - border_styles.push(Some(border_style)); - } - }); - - let borders = - generate_borders_full(sheet, ®ion, border_selections, border_styles); - ops.push(Operation::SetBorders { region, borders }); - } - }); - - self.set_in_progress_transaction(ops, cursor, compute, TransactionType::Normal) - } - - fn paste_plain_text( - &mut self, - sheet_id: SheetId, - start_pos: Pos, - clipboard: String, - cursor: Option, - ) -> TransactionSummary { - let lines: Vec<&str> = clipboard.split('\n').collect(); - - let mut operations = vec![]; - - let cell_values = lines - .iter() - .enumerate() - .map(|(x, line)| { - line.split('\t') - .enumerate() - .map(|(y, value)| { - self.string_to_cell_value( - sheet_id, - (start_pos.x + x as i64, start_pos.y + y as i64).into(), - value, - &mut operations, - ) - }) - .collect::>() - }) - .collect::>>(); - - let array = Array::from(cell_values); - - let rect = crate::Rect::new_span( - start_pos, - ( - start_pos.x + array.width() as i64 - 1, - start_pos.y + array.height() as i64 - 1, - ) - .into(), - ); - - operations.push(Operation::SetCellValues { - region: self.region(sheet_id, rect), - values: array, - }); - - self.set_in_progress_transaction(operations, cursor, true, TransactionType::Normal) - } - - // todo: parse table structure to provide better pasting experience from other spreadsheets - fn paste_html( - &mut self, - sheet_id: SheetId, - pos: Pos, - html: String, - cursor: Option, - ) -> Result { - // use regex to find data-quadratic - let re = Regex::new(r#"data-quadratic="(.*)">(&unencoded.unwrap()); - if parsed.is_err() { - return Err(()); - } - let clipboard = parsed.unwrap(); - Ok(self.set_clipboard_cells(sheet_id, pos, clipboard, cursor)) + let (ops, plain_text, html) = self.cut_to_clipboard_operations(sheet_rect); + let summary = self.set_in_progress_transaction(ops, cursor, false, TransactionType::User); + (summary, plain_text, html) } pub fn paste_from_clipboard( &mut self, - sheet_id: SheetId, - pos: Pos, + sheet_pos: SheetPos, plain_text: Option, html: Option, cursor: Option, ) -> TransactionSummary { // first try html if let Some(html) = html { - let pasted_html = self.paste_html(sheet_id, pos, html, cursor.clone()); - if let Ok(pasted_html) = pasted_html { - return pasted_html; + if let Ok(ops) = self.paste_html_operations(sheet_pos, html) { + self.set_in_progress_transaction(ops, cursor, true, TransactionType::User) + } else { + TransactionSummary::default() } } - // if not quadratic html, then use the plain text // first try html - if let Some(plain_text) = plain_text { - return self.paste_plain_text(sheet_id, pos, plain_text, cursor); + else if let Some(plain_text) = plain_text { + let ops = self.paste_plain_text_operations(sheet_pos, plain_text); + self.set_in_progress_transaction(ops, cursor, true, TransactionType::User) + } else { + TransactionSummary::default() } - TransactionSummary::default() } } @@ -398,10 +163,10 @@ mod test { color::Rgba, controller::GridController, grid::{ - generate_borders, js_types::CellFormatSummary, set_region_borders, BorderSelection, + generate_borders, js_types::CellFormatSummary, set_rect_borders, BorderSelection, BorderStyle, CellBorderLine, CodeCellLanguage, Sheet, }, - CellValue, Pos, Rect, + CellValue, Pos, Rect, SheetPos, SheetRect, }; fn set_borders(sheet: &mut Sheet) { @@ -411,9 +176,8 @@ mod test { line: CellBorderLine::Line1, }; let rect = Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 0, y: 0 }); - let region = sheet.region(rect); - let borders = generate_borders(sheet, ®ion, selection, Some(style)); - set_region_borders(sheet, vec![region.clone()], borders); + let borders = generate_borders(sheet, &rect, selection, Some(style)); + set_rect_borders(sheet, &rect, borders); } #[test] @@ -421,45 +185,65 @@ mod test { let mut gc = GridController::default(); let sheet_id = gc.sheet_ids()[0]; - gc.set_cell_value(sheet_id, Pos { x: 1, y: 1 }, String::from("1, 1"), None); + gc.set_cell_value( + SheetPos { + x: 1, + y: 1, + sheet_id, + }, + String::from("1, 1"), + None, + ); gc.set_cell_bold( - sheet_id, - Rect { + SheetRect { min: Pos { x: 1, y: 1 }, max: Pos { x: 1, y: 1 }, + sheet_id, }, Some(true), None, ); - gc.set_cell_value(sheet_id, Pos { x: 3, y: 2 }, String::from("12"), None); + gc.set_cell_value( + SheetPos { + x: 3, + y: 2, + sheet_id, + }, + String::from("12"), + None, + ); gc.set_cell_italic( - sheet_id, - Rect { + SheetRect { min: Pos { x: 3, y: 2 }, max: Pos { x: 3, y: 2 }, + sheet_id, }, Some(true), None, ); - let rect = Rect { + let sheet_rect = SheetRect { min: Pos { x: 1, y: 1 }, max: Pos { x: 3, y: 2 }, + sheet_id, }; - let (plain_text, _) = gc.copy_to_clipboard(sheet_id, rect); + let (plain_text, _) = gc.copy_to_clipboard(sheet_rect); assert_eq!(plain_text, String::from("1, 1\t\t\n\t\t12")); - let rect = Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 3, y: 3 }); - let clipboard = gc.copy_to_clipboard(sheet_id, rect); + let sheet_rect = SheetRect::new_pos_span(Pos { x: 0, y: 0 }, Pos { x: 3, y: 3 }, sheet_id); + let clipboard = gc.copy_to_clipboard(sheet_rect); // paste using plain_text let mut gc = GridController::default(); let sheet_id = gc.sheet_ids()[0]; gc.paste_from_clipboard( - sheet_id, - Pos { x: 0, y: 0 }, + SheetPos { + x: 0, + y: 0, + sheet_id, + }, Some(clipboard.clone().0), None, None, @@ -478,8 +262,11 @@ mod test { let mut gc = GridController::default(); let sheet_id = gc.sheet_ids()[0]; gc.paste_from_clipboard( - sheet_id, - Pos { x: 0, y: 0 }, + SheetPos { + x: 0, + y: 0, + sheet_id, + }, Some(String::from("")), Some(clipboard.clone().1), None, @@ -522,8 +309,11 @@ mod test { let sheet_id = gc.sheet_ids()[0]; gc.set_cell_code( - sheet_id, - Pos { x: 1, y: 1 }, + SheetPos { + x: 1, + y: 1, + sheet_id, + }, CodeCellLanguage::Formula, String::from("1 + 1"), None, @@ -531,8 +321,8 @@ mod test { assert_eq!(gc.undo_stack.len(), 1); - let rect = Rect::new_span(Pos { x: 1, y: 1 }, Pos { x: 1, y: 1 }); - let clipboard = gc.copy_to_clipboard(sheet_id, rect); + let sheet_rect = SheetRect::new_pos_span(Pos { x: 1, y: 1 }, Pos { x: 1, y: 1 }, sheet_id); + let clipboard = gc.copy_to_clipboard(sheet_rect); // paste using html let mut gc = GridController::default(); @@ -542,8 +332,11 @@ mod test { // overwrite an existing code cell gc.set_cell_code( - sheet_id, - Pos { x: 0, y: 0 }, + SheetPos { + x: 0, + y: 0, + sheet_id, + }, CodeCellLanguage::Formula, String::from("2 + 2"), None, @@ -552,8 +345,11 @@ mod test { assert_eq!(gc.undo_stack.len(), 1); gc.paste_from_clipboard( - sheet_id, - Pos { x: 0, y: 0 }, + SheetPos { + x: 0, + y: 0, + sheet_id, + }, Some(String::from("")), Some(clipboard.1), None, @@ -592,12 +388,15 @@ mod test { set_borders(sheet); - let rect = Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 0, y: 0 }); - let clipboard = gc.copy_to_clipboard(sheet_id, rect); + let sheet_rect = SheetRect::new_pos_span(Pos { x: 0, y: 0 }, Pos { x: 0, y: 0 }, sheet_id); + let clipboard = gc.copy_to_clipboard(sheet_rect); gc.paste_from_clipboard( - sheet_id, - Pos { x: 3, y: 3 }, + SheetPos { + x: 3, + y: 3, + sheet_id, + }, Some(String::from("")), Some(clipboard.1), None, @@ -630,9 +429,8 @@ mod test { line: CellBorderLine::Line1, }; let rect = Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 4, y: 4 }); - let region = sheet.region(rect); - let borders = generate_borders(sheet, ®ion, selection, Some(style)); - set_region_borders(sheet, vec![region.clone()], borders); + let borders = generate_borders(sheet, &rect, selection, Some(style)); + set_rect_borders(sheet, &rect, borders); // weird: can't test them by comparing arrays since the order is seemingly random let render = gc.get_render_borders(sheet_id.to_string()); @@ -666,11 +464,21 @@ mod test { && border.style == style })); - let (_, html) = gc.copy_to_clipboard( + let (_, html) = gc.copy_to_clipboard(SheetRect::new_pos_span( + Pos { x: 0, y: 0 }, + Pos { x: 4, y: 4 }, sheet_id, - Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 4, y: 4 }), + )); + let _ = gc.paste_from_clipboard( + SheetPos { + x: 0, + y: 10, + sheet_id, + }, + None, + Some(html), + None, ); - let _ = gc.paste_html(sheet_id, Pos { x: 0, y: 10 }, html, None); let render = gc.get_render_borders(sheet_id.to_string()); assert!(render.get_horizontal().iter().any(|border| { @@ -714,8 +522,11 @@ mod test { ); gc.paste_from_clipboard( - sheet_id, - Pos { x: 1, y: 2 }, + SheetPos { + x: 1, + y: 2, + sheet_id, + }, None, Some(pasted_output), None, diff --git a/quadratic-core/src/controller/formatting.rs b/quadratic-core/src/controller/user_actions/formatting.rs similarity index 63% rename from quadratic-core/src/controller/formatting.rs rename to quadratic-core/src/controller/user_actions/formatting.rs index d2ec2513a2..9b96806e34 100644 --- a/quadratic-core/src/controller/formatting.rs +++ b/quadratic-core/src/controller/user_actions/formatting.rs @@ -1,154 +1,75 @@ -use std::collections::HashSet; - +use crate::controller::{ + execution::TransactionType, operations::operation::Operation, + transaction_summary::TransactionSummary, GridController, +}; use crate::{ grid::{ - Bold, CellAlign, CellFmtAttr, CellWrap, FillColor, Italic, NumericCommas, NumericDecimals, - NumericFormat, NumericFormatKind, RegionRef, RenderSize, SheetId, TextColor, + formatting::CellFmtArray, Bold, CellAlign, CellFmtAttr, CellWrap, FillColor, Italic, + NumericCommas, NumericDecimals, NumericFormat, RenderSize, TextColor, }, - Pos, Rect, RunLengthEncoding, -}; -use serde::{Deserialize, Serialize}; - -use super::{ - operation::Operation, - transaction_summary::{CellSheetsModified, TransactionSummary}, - transactions::TransactionType, - GridController, + Pos, RunLengthEncoding, SheetPos, SheetRect, }; impl GridController { pub fn set_cell_formats_for_type( &mut self, - region: &RegionRef, + sheet_rect: &SheetRect, values: RunLengthEncoding>, - cell_sheets_modified: Option<&mut HashSet>, + update_cell_sheets_modified: bool, ) -> RunLengthEncoding> { - let sheet = self.grid.sheet_mut_from_id(region.sheet); - // TODO: optimize this for contiguous runs of the same value - let mut old_values = RunLengthEncoding::new(); - for (cell_ref, value) in region.iter().zip(values.iter_values()) { - let old_value = sheet - .cell_ref_to_pos(cell_ref) - .and_then(|pos| sheet.set_formatting_value::(pos, value.clone())); - old_values.push(old_value); + let sheet = self.grid.sheet_mut_from_id(sheet_rect.sheet_id); + let results = sheet.set_cell_formats_for_type::(sheet_rect, values); + if update_cell_sheets_modified { + self.add_cell_sheets_modified_rect(sheet_rect); } - if let Some(cell_sheets_modified) = cell_sheets_modified { - CellSheetsModified::add_region(cell_sheets_modified, sheet, region); - } - old_values + results } /// set currency type for a region /// this also resets NumericDecimals to 2 pub fn set_currency( &mut self, - sheet_id: SheetId, - rect: &Rect, + sheet_rect: &SheetRect, symbol: Option, cursor: Option, ) -> TransactionSummary { - let region = self.grid_mut().sheet_mut_from_id(sheet_id).region(*rect); - let ops = vec![ - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( - Some(NumericFormat { - kind: NumericFormatKind::Currency, - symbol, - }), - region.len(), - )), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat( - Some(2), - region.len(), - )), - }, - ]; - self.set_in_progress_transaction(ops, cursor, false, TransactionType::Normal) + let ops = self.set_currency_operations(sheet_rect, symbol); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) } /// Sets NumericFormat and NumericDecimals to None pub fn remove_number_formatting( &mut self, - sheet_id: SheetId, - rect: &Rect, + sheet_rect: &SheetRect, cursor: Option, ) -> TransactionSummary { - let region = self.grid_mut().sheet_mut_from_id(sheet_id).region(*rect); - let ops = vec![ - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat(None, region.len())), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat(None, region.len())), - }, - Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericCommas(RunLengthEncoding::repeat(None, region.len())), - }, - ]; - self.set_in_progress_transaction(ops, cursor, false, TransactionType::Normal) + let ops = self.remove_number_formatting_operations(sheet_rect); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) } - // todo: should also check the results of spills pub fn change_decimal_places( &mut self, - sheet_id: SheetId, - source: Pos, - rect: Rect, + source: SheetPos, + sheet_rect: SheetRect, delta: isize, cursor: Option, ) -> TransactionSummary { - let sheet = self.sheet(sheet_id); - let is_percentage = - sheet.cell_numeric_format_kind(source) == Some(NumericFormatKind::Percentage); - let decimals = sheet.decimal_places(source, is_percentage).unwrap_or(0); - if decimals + (delta as i16) < 0 { - return TransactionSummary::default(); - } - let region = self.region(sheet_id, rect); - let numeric_decimals = Some(decimals + delta as i16); - let ops = vec![Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat( - numeric_decimals, - region.len(), - )), - }]; - self.set_in_progress_transaction(ops, cursor, false, TransactionType::Normal) + let ops = self.change_decimal_places_operations(source, sheet_rect, delta); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) } pub fn toggle_commas( &mut self, - sheet_id: SheetId, - source: Pos, - rect: Rect, + source: SheetPos, + sheet_rect: SheetRect, cursor: Option, ) -> TransactionSummary { - let sheet = self.sheet(sheet_id); - let commas = if let Some(commas) = sheet.get_formatting_value::(source) { - !commas - } else { - true - }; - let region = self.region(sheet_id, rect); - let ops = vec![Operation::SetCellFormats { - region: region.clone(), - attr: CellFmtArray::NumericCommas(RunLengthEncoding::repeat( - Some(commas), - region.len(), - )), - }]; - self.set_in_progress_transaction(ops, cursor, false, TransactionType::Normal) + let ops = self.toggle_commas_operations(source, sheet_rect); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) } - pub fn get_all_cell_formats(&self, sheet_id: SheetId, rect: Rect) -> Vec { - let sheet = self.sheet(sheet_id); + pub fn get_all_cell_formats(&self, sheet_rect: SheetRect) -> Vec { + let sheet = self.sheet(sheet_rect.sheet_id); let mut cell_formats = vec![ CellFmtArray::Align(RunLengthEncoding::new()), CellFmtArray::Wrap(RunLengthEncoding::new()), @@ -160,8 +81,8 @@ impl GridController { CellFmtArray::TextColor(RunLengthEncoding::new()), CellFmtArray::FillColor(RunLengthEncoding::new()), ]; - for y in rect.y_range() { - for x in rect.x_range() { + for y in sheet_rect.y_range() { + for x in sheet_rect.x_range() { let pos = Pos { x, y }; cell_formats.iter_mut().for_each(|array| match array { CellFmtArray::Align(array) => { @@ -206,15 +127,13 @@ macro_rules! impl_set_cell_fmt_method { impl GridController { pub fn $method_name( &mut self, - sheet_id: SheetId, - rect: Rect, + sheet_rect: SheetRect, value: Option<<$cell_fmt_attr_type as CellFmtAttr>::Value>, cursor: Option, ) -> TransactionSummary { - let region = self.region(sheet_id, rect); let attr = - $cell_fmt_array_constructor(RunLengthEncoding::repeat(value, region.len())); - let ops = vec![Operation::SetCellFormats { region, attr }]; + $cell_fmt_array_constructor(RunLengthEncoding::repeat(value, sheet_rect.len())); + let ops = vec![Operation::SetCellFormats { sheet_rect, attr }]; self.set_in_progress_transaction(ops, cursor, false, TransactionType::Normal) } } @@ -231,27 +150,12 @@ impl_set_cell_fmt_method!(set_cell_text_color(CellFmtArray::TextColor impl_set_cell_fmt_method!(set_cell_fill_color(CellFmtArray::FillColor)); impl_set_cell_fmt_method!(set_cell_render_size(CellFmtArray::RenderSize)); -/// Array of a single cell formatting attribute. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] -pub enum CellFmtArray { - Align(RunLengthEncoding>), - Wrap(RunLengthEncoding>), - NumericFormat(RunLengthEncoding>), - NumericDecimals(RunLengthEncoding>), - NumericCommas(RunLengthEncoding>), - Bold(RunLengthEncoding>), - Italic(RunLengthEncoding>), - TextColor(RunLengthEncoding>), - FillColor(RunLengthEncoding>), - RenderSize(RunLengthEncoding>), -} - #[cfg(test)] mod test { use crate::{ controller::GridController, grid::{RenderSize, TextColor}, - Pos, Rect, + Pos, Rect, SheetPos, SheetRect, }; #[test] @@ -261,8 +165,8 @@ mod test { let pos1 = Pos { x: 3, y: 6 }; let pos2 = Pos { x: 5, y: 8 }; let pos3 = Pos { x: 9, y: 6 }; - let rect1 = Rect::new_span(pos1, pos2); - let rect2 = Rect::new_span(pos2, pos3); + let rect1 = SheetRect::new_pos_span(pos1, pos2, sheet_id); + let rect2 = SheetRect::new_pos_span(pos2, pos3, sheet_id); let get = |g: &GridController, pos: crate::Pos| { g.sheet(sheet_id) @@ -274,12 +178,12 @@ mod test { assert_eq!(get(&gc, pos2), ""); assert_eq!(get(&gc, pos3), ""); - gc.set_cell_text_color(sheet_id, rect1, Some("blue".to_string()), None); + gc.set_cell_text_color(rect1, Some("blue".to_string()), None); assert_eq!(get(&gc, pos1), "blue"); assert_eq!(get(&gc, pos2), "blue"); assert_eq!(get(&gc, pos3), ""); - gc.set_cell_text_color(sheet_id, rect2, Some("red".to_string()), None); + gc.set_cell_text_color(rect2, Some("red".to_string()), None); assert_eq!(get(&gc, pos1), "blue"); assert_eq!(get(&gc, pos2), "red"); assert_eq!(get(&gc, pos3), "red"); @@ -305,12 +209,12 @@ mod test { assert_eq!(get(&gc, pos3), "red"); // delete and redo - gc.delete_cells_rect(sheet_id, rect1, None); + gc.delete_cells_rect(rect1, None); assert_eq!(get(&gc, pos1), "blue"); assert_eq!(get(&gc, pos2), "red"); assert_eq!(get(&gc, pos3), "red"); - gc.clear_formatting(sheet_id, rect1, None); + gc.clear_formatting(rect1, None); assert_eq!(get(&gc, pos1), ""); assert_eq!(get(&gc, pos2), ""); assert_eq!(get(&gc, pos3), "red"); @@ -331,28 +235,28 @@ mod test { let mut gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; gc.set_cell_fill_color( - sheet_id, - Rect { + SheetRect { min: crate::Pos { x: 1, y: 1 }, max: crate::Pos { x: 10, y: 10 }, + sheet_id, }, Some("blue".to_string()), None, ); gc.set_cell_fill_color( - sheet_id, - Rect { + SheetRect { min: crate::Pos { x: 1, y: 15 }, max: crate::Pos { x: 10, y: 20 }, + sheet_id, }, Some("blue".to_string()), None, ); gc.set_cell_fill_color( - sheet_id, - Rect { + SheetRect { min: crate::Pos { x: 1, y: 10 }, max: crate::Pos { x: 10, y: 15 }, + sheet_id, }, Some("blue".to_string()), None, @@ -370,18 +274,32 @@ mod test { let mut gc: GridController = GridController::new(); let sheet_id = gc.sheet_ids()[0]; gc.set_cell_value( - sheet_id, - Pos { x: 0, y: 0 }, + SheetPos { + x: 0, + y: 0, + sheet_id, + }, String::from("1.12345678"), None, ); gc.set_cell_value( - sheet_id, - Pos { x: 1, y: 0 }, + SheetPos { + x: 1, + y: 0, + sheet_id, + }, String::from("0.12345678"), None, ); - gc.set_cell_value(sheet_id, Pos { x: 0, y: 1 }, String::from("abcd"), None); + gc.set_cell_value( + SheetPos { + x: 0, + y: 1, + sheet_id, + }, + String::from("abcd"), + None, + ); let cells = gc .sheet(sheet_id) .get_render_cells(Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 1, y: 1 })); @@ -392,9 +310,12 @@ mod test { // delta: -1 for two cells gc.change_decimal_places( - sheet_id, - Pos { x: 0, y: 0 }, - Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 1, y: 1 }), + SheetPos { + x: 0, + y: 0, + sheet_id, + }, + SheetRect::new_pos_span(Pos { x: 0, y: 0 }, Pos { x: 1, y: 1 }, sheet_id), -1, None, ); @@ -408,9 +329,12 @@ mod test { // delta +1 for two cells gc.change_decimal_places( - sheet_id, - Pos { x: 0, y: 0 }, - Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 1, y: 1 }), + SheetPos { + x: 0, + y: 0, + sheet_id, + }, + SheetRect::new_pos_span(Pos { x: 0, y: 0 }, Pos { x: 1, y: 1 }, sheet_id), 1, None, ); @@ -428,14 +352,16 @@ mod test { let mut gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; gc.set_cell_value( - sheet_id, - Pos { x: 0, y: 0 }, + SheetPos { + x: 0, + y: 0, + sheet_id, + }, String::from("1.12345678"), None, ); gc.set_currency( - sheet_id, - &Rect::single_pos(Pos { x: 0, y: 0 }), + &SheetRect::single_pos(Pos { x: 0, y: 0 }, sheet_id), Some("$".to_string()), None, ); @@ -451,8 +377,7 @@ mod test { let mut gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; gc.set_cell_render_size( - sheet_id, - Rect::single_pos(Pos { x: 0, y: 0 }), + SheetRect::single_pos(Pos { x: 0, y: 0 }, sheet_id), Some(RenderSize { w: "1".to_string(), h: "2".to_string(), @@ -466,18 +391,20 @@ mod test { let mut gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; gc.set_cell_value( - sheet_id, - Pos { x: 0, y: 0 }, + SheetPos { + x: 0, + y: 0, + sheet_id, + }, String::from("1.12345678"), None, ); gc.set_currency( - sheet_id, - &Rect::single_pos(Pos { x: 0, y: 0 }), + &SheetRect::single_pos(Pos { x: 0, y: 0 }, sheet_id), Some("$".to_string()), None, ); - gc.clear_formatting(sheet_id, Rect::single_pos(Pos { x: 0, y: 0 }), None); + gc.clear_formatting(SheetRect::single_pos(Pos { x: 0, y: 0 }, sheet_id), None); let cells = gc .sheet(sheet_id) .get_render_cells(Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 0, y: 0 })); @@ -490,8 +417,7 @@ mod test { let mut gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; gc.set_cell_render_size( - sheet_id, - Rect::single_pos(Pos { x: 0, y: 0 }), + SheetRect::single_pos(Pos { x: 0, y: 0 }, sheet_id), Some(RenderSize { w: "1".to_string(), h: "2".to_string(), diff --git a/quadratic-core/src/controller/import.rs b/quadratic-core/src/controller/user_actions/import.rs similarity index 52% rename from quadratic-core/src/controller/import.rs rename to quadratic-core/src/controller/user_actions/import.rs index 3a105b326a..f27fd64cd5 100644 --- a/quadratic-core/src/controller/import.rs +++ b/quadratic-core/src/controller/user_actions/import.rs @@ -1,9 +1,8 @@ -use anyhow::{anyhow, bail, Result}; - -use super::{ - transaction_summary::TransactionSummary, transactions::TransactionType, GridController, +use crate::controller::{ + execution::TransactionType, transaction_summary::TransactionSummary, GridController, }; -use crate::{controller::operation::Operation, grid::SheetId, Array, CellValue, Pos}; +use crate::{grid::SheetId, Pos}; +use anyhow::Result; impl GridController { /// Imports a CSV file into the grid. @@ -17,57 +16,8 @@ impl GridController { insert_at: Pos, cursor: Option, ) -> Result { - let error = |message: String| anyhow!("Error parsing CSV file {}: {}", file_name, message); - let width = csv::ReaderBuilder::new().from_reader(file).headers()?.len() as u32; - - if width == 0 { - bail!("empty files cannot be processed"); - } - - let mut reader = csv::ReaderBuilder::new() - .has_headers(false) - .from_reader(file); - - let mut ops = vec![] as Vec; - - let cell_values = reader - .records() - .enumerate() - .flat_map(|(row, record)| { - // convert the record into a vector of Operations - record - .map_err(|e| error(format!("line {}: {}", row + 1, e)))? - .iter() - .enumerate() - .map(|(col, value)| { - Ok(self.string_to_cell_value( - sheet_id, - (insert_at.x + col as i64, insert_at.y + row as i64).into(), - value, - &mut ops, - )) - }) - .collect::>>() - }) - .collect::>>(); - - let array = Array::from(cell_values); - - let rect = crate::Rect::new_span( - insert_at, - ( - insert_at.x + array.width() as i64 - 1, - insert_at.y + array.height() as i64 - 1, - ) - .into(), - ); - - ops.push(Operation::SetCellValues { - region: self.region(sheet_id, rect), - values: array, - }); - - Ok(self.set_in_progress_transaction(ops, cursor, true, TransactionType::Normal)) + let ops = self.import_csv_operations(sheet_id, file, file_name, insert_at)?; + Ok(self.set_in_progress_transaction(ops, cursor, true, TransactionType::User)) } } diff --git a/quadratic-core/src/controller/user_actions/mod.rs b/quadratic-core/src/controller/user_actions/mod.rs new file mode 100644 index 0000000000..85dc8660ea --- /dev/null +++ b/quadratic-core/src/controller/user_actions/mod.rs @@ -0,0 +1,10 @@ +/// These are all user-initiated actions on the grid. +/// +pub mod auto_complete; +pub mod borders; +pub mod cells; +pub mod clipboard; +pub mod formatting; +pub mod import; +pub mod sheets; +pub mod undo; diff --git a/quadratic-core/src/controller/user_actions/sheets.rs b/quadratic-core/src/controller/user_actions/sheets.rs new file mode 100644 index 0000000000..ecc47a2c94 --- /dev/null +++ b/quadratic-core/src/controller/user_actions/sheets.rs @@ -0,0 +1,150 @@ +use crate::{ + controller::{ + execution::TransactionType, transaction_summary::TransactionSummary, GridController, + }, + grid::SheetId, +}; + +impl GridController { + pub fn set_sheet_name( + &mut self, + sheet_id: SheetId, + name: String, + cursor: Option, + ) -> TransactionSummary { + let ops = self.set_sheet_name_operations(sheet_id, name); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) + } + + pub fn set_sheet_color( + &mut self, + sheet_id: SheetId, + color: Option, + cursor: Option, + ) -> TransactionSummary { + let ops = self.set_sheet_color_operations(sheet_id, color); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) + } + + pub fn add_sheet(&mut self, cursor: Option) -> TransactionSummary { + let ops = self.add_sheet_operations(); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) + } + pub fn delete_sheet( + &mut self, + sheet_id: SheetId, + cursor: Option, + ) -> TransactionSummary { + let ops = self.delete_sheet_operations(sheet_id); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) + } + pub fn move_sheet( + &mut self, + sheet_id: SheetId, + to_before: Option, + cursor: Option, + ) -> TransactionSummary { + let ops = self.move_sheet_operations(sheet_id, to_before); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) + } + pub fn duplicate_sheet( + &mut self, + sheet_id: SheetId, + cursor: Option, + ) -> TransactionSummary { + let ops = self.duplicate_sheet_operations(sheet_id); + self.set_in_progress_transaction(ops, cursor, false, TransactionType::User) + } +} + +#[cfg(test)] +mod test { + use crate::{controller::GridController, grid::SheetId}; + + #[test] + fn test_add_delete_reorder_sheets() { + let mut g = GridController::new(); + g.add_sheet(None); + g.add_sheet(None); + let old_sheet_ids = g.sheet_ids(); + let s1 = old_sheet_ids[0]; + let s2 = old_sheet_ids[1]; + let s3 = old_sheet_ids[2]; + + fn test_reorder( + g: &mut GridController, + a: SheetId, + b: Option, + expected: [SheetId; 3], + old_sheet_ids: &Vec, + ) { + g.move_sheet(a, b, None); + assert_eq!(expected.to_vec(), g.sheet_ids()); + g.undo(None); + assert_eq!(*old_sheet_ids, g.sheet_ids()); + } + + test_reorder(&mut g, s1, Some(s2), [s1, s2, s3], &old_sheet_ids); + test_reorder(&mut g, s1, Some(s3), [s2, s1, s3], &old_sheet_ids); + test_reorder(&mut g, s1, None, [s2, s3, s1], &old_sheet_ids); + test_reorder(&mut g, s2, Some(s1), [s2, s1, s3], &old_sheet_ids); + test_reorder(&mut g, s2, Some(s3), [s1, s2, s3], &old_sheet_ids); + test_reorder(&mut g, s2, None, [s1, s3, s2], &old_sheet_ids); + test_reorder(&mut g, s3, Some(s1), [s3, s1, s2], &old_sheet_ids); + test_reorder(&mut g, s3, Some(s2), [s1, s3, s2], &old_sheet_ids); + test_reorder(&mut g, s3, None, [s1, s2, s3], &old_sheet_ids); + + fn test_delete( + g: &mut GridController, + a: SheetId, + expected: [SheetId; 2], + old_sheet_ids: &Vec, + ) { + g.delete_sheet(a, None); + assert_eq!(expected.to_vec(), g.sheet_ids()); + g.undo(None); + assert_eq!(*old_sheet_ids, g.sheet_ids()); + } + + test_delete(&mut g, s1, [s2, s3], &old_sheet_ids); + test_delete(&mut g, s2, [s1, s3], &old_sheet_ids); + test_delete(&mut g, s3, [s1, s2], &old_sheet_ids); + } + + #[test] + fn test_duplicate_sheet() { + let mut g = GridController::new(); + let old_sheet_ids = g.sheet_ids(); + let s1 = old_sheet_ids[0]; + + g.set_sheet_name(s1, String::from("Nice Name"), None); + g.duplicate_sheet(s1, None); + let sheet_ids = g.sheet_ids(); + let s2 = sheet_ids[1]; + + let sheet1 = g.sheet(s1); + let sheet2 = g.sheet(s2); + + assert_eq!(sheet2.name, format!("{} Copy", sheet1.name)); + } + + #[test] + fn test_delete_last_sheet() { + let mut g = GridController::new(); + let sheet_ids = g.sheet_ids(); + let first_sheet_id = sheet_ids[0]; + + g.delete_sheet(first_sheet_id, None); + let new_sheet_ids = g.sheet_ids(); + assert_eq!(new_sheet_ids.len(), 1); + assert_ne!(new_sheet_ids[0], sheet_ids[0]); + + g.undo(None); + let new_sheet_ids_2 = g.sheet_ids(); + assert_eq!(sheet_ids[0], new_sheet_ids_2[0]); + + g.redo(None); + let new_sheet_ids_3 = g.sheet_ids(); + assert_eq!(new_sheet_ids[0], new_sheet_ids_3[0]); + } +} diff --git a/quadratic-core/src/controller/user_actions/undo.rs b/quadratic-core/src/controller/user_actions/undo.rs new file mode 100644 index 0000000000..ffaab4f4c6 --- /dev/null +++ b/quadratic-core/src/controller/user_actions/undo.rs @@ -0,0 +1,40 @@ +use crate::controller::{ + execution::TransactionType, transaction_summary::TransactionSummary, GridController, +}; + +impl GridController { + pub fn has_undo(&self) -> bool { + !self.undo_stack.is_empty() + } + pub fn has_redo(&self) -> bool { + !self.redo_stack.is_empty() + } + pub fn undo(&mut self, cursor: Option) -> TransactionSummary { + if let Some(transaction) = self.undo_stack.pop() { + let mut summary = self.set_in_progress_transaction( + transaction.operations, + cursor, + false, + TransactionType::Undo, + ); + summary.cursor = transaction.cursor; + summary + } else { + TransactionSummary::default() + } + } + pub fn redo(&mut self, cursor: Option) -> TransactionSummary { + if let Some(transaction) = self.redo_stack.pop() { + let mut summary = self.set_in_progress_transaction( + transaction.operations, + cursor, + false, + TransactionType::Redo, + ); + summary.cursor = transaction.cursor; + summary + } else { + TransactionSummary::default() + } + } +} diff --git a/quadratic-core/src/formulas/ast.rs b/quadratic-core/src/formulas/ast.rs index 4aa9583211..c77b6ee3ca 100644 --- a/quadratic-core/src/formulas/ast.rs +++ b/quadratic-core/src/formulas/ast.rs @@ -115,8 +115,8 @@ impl AstNode { let ref1 = args[0].to_cell_ref()?; let ref2 = args[1].to_cell_ref()?; let sheet_name = ref1.sheet.clone(); - let corner1 = ref1.resolve_from(ctx.pos.without_sheet()); - let corner2 = ref2.resolve_from(ctx.pos.without_sheet()); + let corner1 = ref1.resolve_from(ctx.sheet_pos.into()); + let corner2 = ref2.resolve_from(ctx.sheet_pos.into()); let x1 = std::cmp::min(corner1.x, corner2.x); let y1 = std::cmp::min(corner1.y, corner2.y); diff --git a/quadratic-core/src/formulas/ctx.rs b/quadratic-core/src/formulas/ctx.rs index e1d58ce9ba..32dc96aabc 100644 --- a/quadratic-core/src/formulas/ctx.rs +++ b/quadratic-core/src/formulas/ctx.rs @@ -10,16 +10,16 @@ pub struct Ctx<'ctx> { /// Grid file to access cells from. pub grid: &'ctx Grid, /// Position in the grid from which the formula is being evaluated. - pub pos: SheetPos, + pub sheet_pos: SheetPos, /// Cells that have been accessed in evaluating the formula. pub cells_accessed: HashSet, } impl<'ctx> Ctx<'ctx> { /// Constructs a context for evaluating a formula at `pos` in `grid`. - pub fn new(grid: &'ctx Grid, pos: SheetPos) -> Self { + pub fn new(grid: &'ctx Grid, sheet_pos: SheetPos) -> Self { Ctx { grid, - pos, + sheet_pos, cells_accessed: HashSet::new(), } } @@ -32,11 +32,11 @@ impl<'ctx> Ctx<'ctx> { .grid .sheet_from_name(sheet_name.clone()) // TODO: should not need clone .ok_or(ErrorMsg::BadCellReference.with_span(span))?, - None => self.grid.sheet_from_id(self.pos.sheet_id), + None => self.grid.sheet_from_id(self.sheet_pos.sheet_id), }; - let ref_pos = ref_pos.resolve_from(self.pos.without_sheet()); - let ref_pos_with_sheet = ref_pos.with_sheet(sheet.id); - if ref_pos_with_sheet == self.pos { + let ref_pos = ref_pos.resolve_from(self.sheet_pos.into()); + let ref_pos_with_sheet = ref_pos.to_sheet_pos(sheet.id); + if ref_pos_with_sheet == self.sheet_pos { return Err(ErrorMsg::CircularReference.with_span(span)); } diff --git a/quadratic-core/src/formulas/functions/logic.rs b/quadratic-core/src/formulas/functions/logic.rs index b9c30082fc..0c1b5eb30f 100644 --- a/quadratic-core/src/formulas/functions/logic.rs +++ b/quadratic-core/src/formulas/functions/logic.rs @@ -86,7 +86,7 @@ fn get_functions() -> Vec { #[cfg(test)] mod tests { - use crate::formulas::tests::*; + use crate::{formulas::tests::*, Pos}; #[test] fn test_formula_if() { @@ -94,13 +94,13 @@ mod tests { let mut g = Grid::new(); let sheet = &mut g.sheets_mut()[0]; - sheet.set_cell_value(Pos { x: 0, y: 1 }, "q"); - sheet.set_cell_value(Pos { x: 1, y: 1 }, "w"); + let _ = sheet.set_cell_value(Pos { x: 0, y: 1 }, "q"); + let _ = sheet.set_cell_value(Pos { x: 1, y: 1 }, "w"); let sheet_id = sheet.id; - let mut ctx = Ctx::new(&g, pos![A0].with_sheet(sheet_id)); + let mut ctx = Ctx::new(&g, pos![A0].to_sheet_pos(sheet_id)); assert_eq!("yep".to_string(), form.eval(&mut ctx).unwrap().to_string()); - let mut ctx = Ctx::new(&g, pos![B0].with_sheet(sheet_id)); + let mut ctx = Ctx::new(&g, pos![B0].to_sheet_pos(sheet_id)); assert_eq!("nope".to_string(), form.eval(&mut ctx).unwrap().to_string()); } } diff --git a/quadratic-core/src/formulas/functions/lookup.rs b/quadratic-core/src/formulas/functions/lookup.rs index 0f4667c70c..044b821a4c 100644 --- a/quadratic-core/src/formulas/functions/lookup.rs +++ b/quadratic-core/src/formulas/functions/lookup.rs @@ -20,7 +20,7 @@ fn get_functions() -> Vec { #[examples("INDIRECT(\"Cn7\")", "INDIRECT(\"F\" & B0)")] #[zip_map] fn INDIRECT(ctx: Ctx, [cellref_string]: (Spanned)) { - let pos = CellRef::parse_a1(&cellref_string.inner, ctx.pos.without_sheet()) + let pos = CellRef::parse_a1(&cellref_string.inner, ctx.sheet_pos.into()) .ok_or(ErrorMsg::BadCellReference.with_span(cellref_string.span))?; ctx.get_cell(&pos, cellref_string.span)?.inner } @@ -463,7 +463,7 @@ mod tests { use lazy_static::lazy_static; use smallvec::smallvec; - use crate::formulas::tests::*; + use crate::{formulas::tests::*, Pos}; lazy_static! { static ref NUMBERS_LOOKUP_ARRAY: Array = array![ @@ -499,10 +499,10 @@ mod tests { let mut g = Grid::new(); let sheet = &mut g.sheets_mut()[0]; - sheet.set_cell_value(pos![D5], 35); + let _ = sheet.set_cell_value(pos![D5], 35); let sheet_id = sheet.id; - let mut ctx = Ctx::new(&g, pos![D5].with_sheet(sheet_id)); + let mut ctx = Ctx::new(&g, pos![D5].to_sheet_pos(sheet_id)); assert_eq!( ErrorMsg::CircularReference, form.eval(&mut ctx).unwrap_err().msg, @@ -1014,8 +1014,8 @@ mod tests { let mut g = Grid::new(); let sheet = &mut g.sheets_mut()[0]; for y in 1..=6 { - sheet.set_cell_value(Pos { x: 0, y }, y); - sheet.set_cell_value(Pos { x: 1, y }, format!("cell #{y}")); + let _ = sheet.set_cell_value(Pos { x: 0, y }, y); + let _ = sheet.set_cell_value(Pos { x: 1, y }, format!("cell #{y}")); } // Test lookup in sorted array diff --git a/quadratic-core/src/formulas/functions/mathematics.rs b/quadratic-core/src/formulas/functions/mathematics.rs index c430b020a7..3e0462479f 100644 --- a/quadratic-core/src/formulas/functions/mathematics.rs +++ b/quadratic-core/src/formulas/functions/mathematics.rs @@ -85,7 +85,7 @@ fn get_functions() -> Vec { #[cfg(test)] mod tests { - use crate::formulas::tests::*; + use crate::{formulas::tests::*, Pos}; #[test] fn test_sum() { @@ -109,8 +109,8 @@ mod tests { let mut g = Grid::new(); let sheet = &mut g.sheets_mut()[0]; - sheet.set_cell_value(pos![A6], "text"); - sheet.set_cell_value(pos![A7], "text"); + let _ = sheet.set_cell_value(pos![A6], "text"); + let _ = sheet.set_cell_value(pos![A7], "text"); // One bad cell reference on its own doesn't cause an error because it's // a 1x1 array. assert_eq!("12", eval_to_string(&g, "SUM(12, A6)")); @@ -168,7 +168,7 @@ mod tests { let g = Grid::new(); assert_eq!("10", eval_to_string(&g, "ABS(-10)")); assert_eq!("10", eval_to_string(&g, "ABS(10)")); - let mut ctx = Ctx::new(&g, Pos::ORIGIN.with_sheet(g.sheets()[0].id)); + let mut ctx = Ctx::new(&g, Pos::ORIGIN.to_sheet_pos(g.sheets()[0].id)); assert_eq!( ErrorMsg::MissingRequiredArgument { func_name: "ABS".into(), @@ -180,7 +180,7 @@ mod tests { .unwrap_err() .msg, ); - let mut ctx = Ctx::new(&g, Pos::ORIGIN.with_sheet(g.sheets()[0].id)); + let mut ctx = Ctx::new(&g, Pos::ORIGIN.to_sheet_pos(g.sheets()[0].id)); assert_eq!( ErrorMsg::TooManyArguments { func_name: "ABS".into(), @@ -199,7 +199,7 @@ mod tests { let g = Grid::new(); crate::util::assert_f64_approx_eq(3.0_f64.sqrt(), &eval_to_string(&g, "SQRT(3)")); assert_eq!("4", eval_to_string(&g, "SQRT(16)")); - let mut ctx = Ctx::new(&g, Pos::ORIGIN.with_sheet(g.sheets()[0].id)); + let mut ctx = Ctx::new(&g, Pos::ORIGIN.to_sheet_pos(g.sheets()[0].id)); assert_eq!( ErrorMsg::MissingRequiredArgument { func_name: "SQRT".into(), @@ -211,7 +211,7 @@ mod tests { .unwrap_err() .msg, ); - let mut ctx = Ctx::new(&g, Pos::ORIGIN.with_sheet(g.sheets()[0].id)); + let mut ctx = Ctx::new(&g, Pos::ORIGIN.to_sheet_pos(g.sheets()[0].id)); assert_eq!( ErrorMsg::TooManyArguments { func_name: "SQRT".into(), @@ -229,7 +229,7 @@ mod tests { fn test_pi() { let g = Grid::new(); assert!(eval_to_string(&g, "PI()").starts_with("3.14159")); - let mut ctx = Ctx::new(&g, Pos::ORIGIN.with_sheet(g.sheets()[0].id)); + let mut ctx = Ctx::new(&g, Pos::ORIGIN.to_sheet_pos(g.sheets()[0].id)); assert_eq!( ErrorMsg::TooManyArguments { func_name: "PI".into(), @@ -247,7 +247,7 @@ mod tests { fn test_tau() { let g = Grid::new(); assert!(eval_to_string(&g, "TAU()").starts_with("6.283")); - let mut ctx = Ctx::new(&g, Pos::ORIGIN.with_sheet(g.sheets()[0].id)); + let mut ctx = Ctx::new(&g, Pos::ORIGIN.to_sheet_pos(g.sheets()[0].id)); assert_eq!( ErrorMsg::TooManyArguments { func_name: "TAU".into(), diff --git a/quadratic-core/src/formulas/functions/statistics.rs b/quadratic-core/src/formulas/functions/statistics.rs index 09bf92a9a4..1d6b9ad22a 100644 --- a/quadratic-core/src/formulas/functions/statistics.rs +++ b/quadratic-core/src/formulas/functions/statistics.rs @@ -122,7 +122,7 @@ fn get_functions() -> Vec { #[cfg(test)] mod tests { - use crate::formulas::tests::*; + use crate::{formulas::tests::*, Pos}; #[test] fn test_formula_average() { @@ -132,12 +132,12 @@ mod tests { let sheet = &mut g.sheets_mut()[0]; for x in 1..=3 { for y in 1..=3 { - sheet.set_cell_value(Pos { x, y }, x * 3 + y); + let _ = sheet.set_cell_value(Pos { x, y }, x * 3 + y); } } let sheet_id = sheet.id; - let mut ctx = Ctx::new(&g, pos![nAn1].with_sheet(sheet_id)); + let mut ctx = Ctx::new(&g, pos![nAn1].to_sheet_pos(sheet_id)); assert_eq!("7.5".to_string(), form.eval(&mut ctx).unwrap().to_string(),); assert_eq!( @@ -170,7 +170,7 @@ mod tests { let mut g = Grid::new(); let sheet = &mut g.sheets_mut()[0]; for y in 0..=10 { - sheet.set_cell_value(Pos { x: 1, y }, y); + let _ = sheet.set_cell_value(Pos { x: 1, y }, y); } assert_eq!("2.5", eval_to_string(&g, "AVERAGEIF(Bn5:B10, \"<=5\")")); } @@ -248,7 +248,7 @@ mod tests { let mut g = Grid::new(); let sheet = &mut g.sheets_mut()[0]; for y in 0..=10 { - sheet.set_cell_value(Pos { x: 1, y }, y); + let _ = sheet.set_cell_value(Pos { x: 1, y }, y); } assert_eq!("6", eval_to_string(&g, "COUNTIF(Bn5:B10, \"<=5\")")); } diff --git a/quadratic-core/src/formulas/tests.rs b/quadratic-core/src/formulas/tests.rs index 04485c32e8..83fb8194e4 100644 --- a/quadratic-core/src/formulas/tests.rs +++ b/quadratic-core/src/formulas/tests.rs @@ -3,7 +3,8 @@ use itertools::Itertools; pub(crate) use super::*; pub(crate) use crate::grid::Grid; pub(crate) use crate::values::*; -pub(crate) use crate::{array, CodeResult, Error, ErrorMsg, Pos, SheetPos, Spanned}; +pub(crate) use crate::{array, CodeResult, Error, ErrorMsg, Spanned}; +use crate::{Pos, SheetPos}; pub(crate) fn try_eval_at(grid: &Grid, pos: SheetPos, s: &str) -> CodeResult { println!("Evaluating formula {s:?} at {pos:?}"); @@ -11,16 +12,16 @@ pub(crate) fn try_eval_at(grid: &Grid, pos: SheetPos, s: &str) -> CodeResult Value { - try_eval_at(grid, pos, s).expect("error evaluating formula") +pub(crate) fn eval_at(grid: &Grid, sheet_pos: SheetPos, s: &str) -> Value { + try_eval_at(grid, sheet_pos, s).expect("error evaluating formula") } #[track_caller] -pub(crate) fn eval_to_string_at(grid: &Grid, pos: SheetPos, s: &str) -> String { - eval_at(grid, pos, s).to_string() +pub(crate) fn eval_to_string_at(grid: &Grid, sheet_pos: SheetPos, s: &str) -> String { + eval_at(grid, sheet_pos, s).to_string() } pub(crate) fn try_eval(grid: &Grid, s: &str) -> CodeResult { - try_eval_at(grid, Pos::ORIGIN.with_sheet(grid.sheets()[0].id), s) + try_eval_at(grid, Pos::ORIGIN.to_sheet_pos(grid.sheets()[0].id), s) } #[track_caller] pub(crate) fn eval(grid: &Grid, s: &str) -> Value { @@ -50,22 +51,22 @@ fn test_formula_cell_ref() { let mut g = Grid::new(); let sheet = &mut g.sheets_mut()[0]; - sheet.set_cell_value(pos![D4], 1); // $D$4 -> D4 - sheet.set_cell_value(pos![Bn2], 10); // $B0 -> Bn2 - sheet.set_cell_value(pos![Cn6], 100); // E$n6 -> Cn6 - sheet.set_cell_value(pos![nAn2], 1000); // B0 -> nAn2 - sheet.set_cell_value(pos![nD0], 10000); // nB2 -> nD0 + let _ = sheet.set_cell_value(pos![D4], 1); // $D$4 -> D4 + let _ = sheet.set_cell_value(pos![Bn2], 10); // $B0 -> Bn2 + let _ = sheet.set_cell_value(pos![Cn6], 100); // E$n6 -> Cn6 + let _ = sheet.set_cell_value(pos![nAn2], 1000); // B0 -> nAn2 + let _ = sheet.set_cell_value(pos![nD0], 10000); // nB2 -> nD0 let sheet_id = sheet.id; // Evaluate at D4, causing a circular reference. - let mut ctx = Ctx::new(&g, pos![D4].with_sheet(sheet_id)); + let mut ctx = Ctx::new(&g, pos![D4].to_sheet_pos(sheet_id)); assert_eq!( ErrorMsg::CircularReference, form.eval(&mut ctx).unwrap_err().msg, ); // Evaluate at B2 - let mut ctx = Ctx::new(&g, pos![B2].with_sheet(sheet_id)); + let mut ctx = Ctx::new(&g, pos![B2].to_sheet_pos(sheet_id)); assert_eq!( "11111".to_string(), form.eval(&mut ctx).unwrap().to_string(), @@ -77,7 +78,7 @@ fn test_formula_circular_array_ref() { let form = parse_formula("$B$0:$C$4", pos![A0]).unwrap(); let g = Grid::new(); - let mut ctx = Ctx::new(&g, pos![B2].with_sheet(g.sheets()[0].id)); + let mut ctx = Ctx::new(&g, pos![B2].to_sheet_pos(g.sheets()[0].id)); assert_eq!( ErrorMsg::CircularReference, @@ -119,7 +120,7 @@ fn test_formula_array_op() { let sheet = &mut g.sheets_mut()[0]; for x in 1..=4 { for y in 1..=4 { - sheet.set_cell_value(Pos { x, y }, x * 10 + y); + let _ = sheet.set_cell_value(Pos { x, y }, x * 10 + y); } } @@ -217,7 +218,7 @@ fn test_leading_equals() { #[test] fn test_hyphen_after_cell_ref() { let mut g = Grid::new(); - g.sheets_mut()[0].set_cell_value(pos![Z1], 30); + let _ = g.sheets_mut()[0].set_cell_value(pos![Z1], 30); assert_eq!("25", eval_to_string(&g, "Z1 - 5")); assert_eq!("25", eval_to_string(&g, "Z1-5")); } @@ -332,13 +333,13 @@ fn test_sheet_references() { let name2 = "My Other Sheet".to_string(); g.sheets_mut()[1].name = name2.clone(); - g.sheet_mut_from_id(id1).set_cell_value(pos![A1], 42); - g.sheet_mut_from_id(id1).set_cell_value(pos![A3], 6); - g.sheet_mut_from_id(id2).set_cell_value(pos![A3], 7); - g.sheet_mut_from_id(id2).set_cell_value(pos![A4], 70); + let _ = g.sheet_mut_from_id(id1).set_cell_value(pos![A1], 42); + let _ = g.sheet_mut_from_id(id1).set_cell_value(pos![A3], 6); + let _ = g.sheet_mut_from_id(id2).set_cell_value(pos![A3], 7); + let _ = g.sheet_mut_from_id(id2).set_cell_value(pos![A4], 70); - let pos1 = Pos::ORIGIN.with_sheet(id1); - let pos2 = Pos::ORIGIN.with_sheet(id2); + let pos1 = Pos::ORIGIN.to_sheet_pos(id1); + let pos2 = Pos::ORIGIN.to_sheet_pos(id2); assert_eq!("426", eval_to_string_at(&g, pos1, "MySheet!A1 & A3")); assert_eq!("427", eval_to_string_at(&g, pos2, "MySheet!A1 & A3")); diff --git a/quadratic-core/src/grid/borders/compute_indices.rs b/quadratic-core/src/grid/borders/compute_indices.rs index 1e7f002092..9de980c5ca 100644 --- a/quadratic-core/src/grid/borders/compute_indices.rs +++ b/quadratic-core/src/grid/borders/compute_indices.rs @@ -3,7 +3,7 @@ use itertools::Itertools; use crate::grid::borders::style::BorderSelection; use crate::Rect; -pub(super) fn vertical(rect: Rect, selections: Vec) -> Vec { +pub(super) fn vertical(rect: &Rect, selections: Vec) -> Vec { selections .iter() .flat_map(|&selection| vertical_selection(rect, selection)) @@ -12,7 +12,7 @@ pub(super) fn vertical(rect: Rect, selections: Vec) -> Vec .collect() } -fn vertical_selection(rect: Rect, selection: BorderSelection) -> Vec { +fn vertical_selection(rect: &Rect, selection: BorderSelection) -> Vec { let first = rect.min.x; let last = rect.max.x + 1; match selection { @@ -26,7 +26,7 @@ fn vertical_selection(rect: Rect, selection: BorderSelection) -> Vec { } } -pub(super) fn horizontal(rect: Rect, selections: Vec) -> Vec { +pub(super) fn horizontal(rect: &Rect, selections: Vec) -> Vec { selections .iter() .flat_map(|&selection| horizontal_selection(rect, selection)) @@ -35,7 +35,7 @@ pub(super) fn horizontal(rect: Rect, selections: Vec) -> Vec Vec { +fn horizontal_selection(rect: &Rect, selection: BorderSelection) -> Vec { let first = rect.min.y; let last = rect.max.y + 1; match selection { @@ -57,72 +57,72 @@ mod tests { #[test] fn horizontal_indices() { - let region = Rect::new_span(Pos { x: 10, y: 20 }, Pos { x: 13, y: 23 }); + let rect = Rect::new_span(Pos { x: 10, y: 20 }, Pos { x: 13, y: 23 }); assert_eq!( - horizontal(region, vec![BorderSelection::All]), + horizontal(&rect, vec![BorderSelection::All]), vec![20, 21, 22, 23, 24] ); assert_eq!( - horizontal(region, vec![BorderSelection::Inner]), + horizontal(&rect, vec![BorderSelection::Inner]), vec![21, 22, 23] ); assert_eq!( - horizontal(region, vec![BorderSelection::Outer]), + horizontal(&rect, vec![BorderSelection::Outer]), vec![20, 24] ); assert_eq!( - horizontal(region, vec![BorderSelection::Horizontal]), + horizontal(&rect, vec![BorderSelection::Horizontal]), vec![21, 22, 23] ); - assert!(horizontal(region, vec![BorderSelection::Vertical]).is_empty()); - assert!(horizontal(region, vec![BorderSelection::Left]).is_empty()); - assert_eq!(horizontal(region, vec![BorderSelection::Top]), vec![20]); - assert!(horizontal(region, vec![BorderSelection::Right]).is_empty()); - assert_eq!(horizontal(region, vec![BorderSelection::Bottom]), vec![24]); + assert!(horizontal(&rect, vec![BorderSelection::Vertical]).is_empty()); + assert!(horizontal(&rect, vec![BorderSelection::Left]).is_empty()); + assert_eq!(horizontal(&rect, vec![BorderSelection::Top]), vec![20]); + assert!(horizontal(&rect, vec![BorderSelection::Right]).is_empty()); + assert_eq!(horizontal(&rect, vec![BorderSelection::Bottom]), vec![24]); assert_eq!( - horizontal(region, vec![BorderSelection::Top, BorderSelection::Bottom]), + horizontal(&rect, vec![BorderSelection::Top, BorderSelection::Bottom]), vec![20, 24] ); assert_eq!( - horizontal(region, vec![BorderSelection::Bottom, BorderSelection::Top]), + horizontal(&rect, vec![BorderSelection::Bottom, BorderSelection::Top]), vec![20, 24] ); - assert!(horizontal(region, vec![BorderSelection::Left, BorderSelection::Right]).is_empty()); + assert!(horizontal(&rect, vec![BorderSelection::Left, BorderSelection::Right]).is_empty()); } #[test] fn vertical_indices() { - let region = Rect::new_span(Pos { x: 10, y: 20 }, Pos { x: 13, y: 23 }); + let rect = Rect::new_span(Pos { x: 10, y: 20 }, Pos { x: 13, y: 23 }); assert_eq!( - vertical(region, vec![BorderSelection::All]), + vertical(&rect, vec![BorderSelection::All]), vec![10, 11, 12, 13, 14] ); assert_eq!( - vertical(region, vec![BorderSelection::Inner]), + vertical(&rect, vec![BorderSelection::Inner]), vec![11, 12, 13] ); - assert_eq!(vertical(region, vec![BorderSelection::Outer]), vec![10, 14]); - assert!(vertical(region, vec![BorderSelection::Horizontal]).is_empty()); + assert_eq!(vertical(&rect, vec![BorderSelection::Outer]), vec![10, 14]); + assert!(vertical(&rect, vec![BorderSelection::Horizontal]).is_empty()); assert_eq!( - vertical(region, vec![BorderSelection::Vertical]), + vertical(&rect, vec![BorderSelection::Vertical]), vec![11, 12, 13] ); - assert_eq!(vertical(region, vec![BorderSelection::Left]), vec![10]); - assert!(vertical(region, vec![BorderSelection::Top]).is_empty()); - assert_eq!(vertical(region, vec![BorderSelection::Right]), vec![14]); - assert!(vertical(region, vec![BorderSelection::Bottom]).is_empty()); + assert_eq!(vertical(&rect, vec![BorderSelection::Left]), vec![10]); + assert!(vertical(&rect, vec![BorderSelection::Top]).is_empty()); + assert_eq!(vertical(&rect, vec![BorderSelection::Right]), vec![14]); + assert!(vertical(&rect, vec![BorderSelection::Bottom]).is_empty()); - assert!(vertical(region, vec![BorderSelection::Top, BorderSelection::Bottom]).is_empty()); + assert!(vertical(&rect, vec![BorderSelection::Top, BorderSelection::Bottom]).is_empty()); assert_eq!( - vertical(region, vec![BorderSelection::Left, BorderSelection::Right]), + vertical(&rect, vec![BorderSelection::Left, BorderSelection::Right]), vec![10, 14] ); assert_eq!( - vertical(region, vec![BorderSelection::Right, BorderSelection::Left]), + vertical(&rect, vec![BorderSelection::Right, BorderSelection::Left]), vec![10, 14] ); } diff --git a/quadratic-core/src/grid/borders/mod.rs b/quadratic-core/src/grid/borders/mod.rs index 099327f220..7e74c4566f 100644 --- a/quadratic-core/src/grid/borders/mod.rs +++ b/quadratic-core/src/grid/borders/mod.rs @@ -2,8 +2,8 @@ pub use cell::{CellBorders, CellSide}; pub use legacy::{LegacyCellBorder, LegacyCellBorders}; pub use render::{get_render_horizontal_borders, get_render_vertical_borders}; pub use sheet::{ - generate_borders, generate_borders_full, get_cell_borders_in_rect, get_region_borders, - set_region_borders, IdSpaceBorders, SheetBorders, + generate_borders, generate_borders_full, get_cell_borders_in_rect, get_rect_borders, + set_rect_borders, IdSpaceBorders, SheetBorders, }; pub use style::{BorderSelection, BorderStyle, CellBorderLine}; diff --git a/quadratic-core/src/grid/borders/render.rs b/quadratic-core/src/grid/borders/render.rs index 49f1b13c22..05faa12e27 100644 --- a/quadratic-core/src/grid/borders/render.rs +++ b/quadratic-core/src/grid/borders/render.rs @@ -42,7 +42,7 @@ mod tests { use std::collections::HashSet; use crate::color::Rgba; - use crate::grid::borders::sheet::set_region_border_selection; + use crate::grid::borders::sheet::set_rect_border_selection; use crate::grid::{BorderSelection, BorderStyle, CellBorderLine, SheetId}; use crate::{Pos, Rect}; @@ -57,7 +57,7 @@ mod tests { // let mut sheet = // Sheet::new(SheetId::new(), "Test Sheet".to_string(), "".to_string()); // let rect = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 506, y: 515 }); - // let region = sheet.region(rect); + // let (region, _) = sheet.region(rect); // // let selection = vec![BorderSelection::All]; // @@ -78,7 +78,7 @@ mod tests { // } mod vertical { - use crate::grid::set_region_borders; + use crate::grid::set_rect_borders; use super::*; @@ -86,7 +86,6 @@ mod tests { fn single_block() { let mut sheet = Sheet::new(SheetId::new(), "Test Sheet".to_string(), "".to_string()); let rect = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 6, y: 15 }); - let region = sheet.region(rect); let selection = vec![BorderSelection::All]; @@ -95,7 +94,7 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion, selection, Some(style)); + set_rect_border_selection(&mut sheet, &rect, selection, Some(style)); let vertical_render = get_render_vertical_borders(&sheet); @@ -115,9 +114,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 4, y: 10 }); let rect_2 = Rect::new_span(Pos { x: 4, y: 11 }, Pos { x: 5, y: 11 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = selection_1.clone(); @@ -126,8 +122,8 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style)); - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style)); let vertical_render = get_render_vertical_borders(&sheet); @@ -149,9 +145,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 6, y: 15 }); let rect_2 = Rect::new_span(Pos { x: 3, y: 17 }, Pos { x: 9, y: 20 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = selection_1.clone(); @@ -160,8 +153,8 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style)); - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style)); let vertical_render = get_render_vertical_borders(&sheet); @@ -193,9 +186,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 6, y: 15 }); let rect_2 = Rect::new_span(Pos { x: 2, y: 11 }, Pos { x: 7, y: 14 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = selection_1.clone(); @@ -208,8 +198,8 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style_1)); - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style_2)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style_1)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style_2)); let vertical_render = get_render_vertical_borders(&sheet); @@ -238,9 +228,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 4, y: 11 }); let rect_2 = Rect::new_span(Pos { x: 5, y: 10 }, Pos { x: 6, y: 11 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = selection_1.clone(); @@ -249,13 +236,12 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style)); let vertical_render_initial = get_render_vertical_borders(&sheet); - let replaced = - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style)); + let replaced = set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style)); - set_region_borders(&mut sheet, vec![region_2], replaced); // Undo + set_rect_borders(&mut sheet, &rect_2, replaced); // Undo let vertical_render_after_undo = get_render_vertical_borders(&sheet); assert_eq!( @@ -273,9 +259,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 6, y: 15 }); let rect_2 = Rect::new_span(Pos { x: 2, y: 11 }, Pos { x: 7, y: 14 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = selection_1.clone(); @@ -288,13 +271,13 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style_1)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style_1)); let vertical_render_initial = get_render_vertical_borders(&sheet); let replaced = - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style_2)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style_2)); - set_region_borders(&mut sheet, vec![region_2], replaced); // Undo + set_rect_borders(&mut sheet, &rect_2, replaced); // Undo let vertical_render_after_undo = get_render_vertical_borders(&sheet); assert_eq!( @@ -308,7 +291,7 @@ mod tests { } mod horizontal { - use crate::grid::set_region_borders; + use crate::grid::set_rect_borders; use super::*; @@ -316,7 +299,6 @@ mod tests { fn single_block() { let mut sheet = Sheet::new(SheetId::new(), "Test Sheet".to_string(), "".to_string()); let rect = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 6, y: 15 }); - let region = sheet.region(rect); let selection = vec![BorderSelection::All]; @@ -325,7 +307,7 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion, selection, Some(style)); + set_rect_border_selection(&mut sheet, &rect, selection, Some(style)); let horizontal_render = get_render_horizontal_borders(&sheet); @@ -345,9 +327,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 3, y: 11 }); let rect_2 = Rect::new_span(Pos { x: 4, y: 11 }, Pos { x: 4, y: 12 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = selection_1.clone(); @@ -356,8 +335,8 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style)); - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style)); let horizontal_render = get_render_horizontal_borders(&sheet); @@ -379,9 +358,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 5, y: 13 }); let rect_2 = Rect::new_span(Pos { x: 7, y: 10 }, Pos { x: 10, y: 15 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = selection_1.clone(); @@ -390,8 +366,8 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style)); - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style)); let horizontal_render = get_render_horizontal_borders(&sheet); @@ -419,9 +395,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 2, y: 11 }, Pos { x: 7, y: 14 }); let rect_2 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 6, y: 15 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = selection_1.clone(); @@ -434,8 +407,8 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style_1)); - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style_2)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style_1)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style_2)); let horizontal_render = get_render_horizontal_borders(&sheet); @@ -464,9 +437,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 2, y: 11 }, Pos { x: 7, y: 14 }); let rect_2 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 6, y: 15 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = selection_1.clone(); @@ -479,13 +449,13 @@ mod tests { line: CellBorderLine::Line1, }; - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style_1)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style_1)); let horizontal_render_initial = get_render_horizontal_borders(&sheet); let replaced = - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style_2)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style_2)); - set_region_borders(&mut sheet, vec![region_2], replaced); // Undo + set_rect_borders(&mut sheet, &rect_2, replaced); // Undo let horizontal_render_after_undo = get_render_horizontal_borders(&sheet); assert_eq!( diff --git a/quadratic-core/src/grid/borders/sheet.rs b/quadratic-core/src/grid/borders/sheet.rs index b98f6e4c22..0f215c4c1a 100644 --- a/quadratic-core/src/grid/borders/sheet.rs +++ b/quadratic-core/src/grid/borders/sheet.rs @@ -1,37 +1,32 @@ use std::collections::HashMap; use std::ops::Range; -use std::str::FromStr; -use itertools::Itertools; use serde::{Deserialize, Serialize}; use crate::grid::block::SameValue; use crate::grid::borders::cell::{CellBorders, CellSide}; use crate::grid::borders::compute_indices; use crate::grid::borders::style::{BorderSelection, BorderStyle}; -use crate::grid::{ColumnData, ColumnId, IdMap, RegionRef, RowId, Sheet}; -use crate::{grid, Rect}; +use crate::grid::{ColumnData, Sheet}; +use crate::{Pos, Rect}; pub fn generate_borders( sheet: &Sheet, - region: &RegionRef, + rect: &Rect, selections: Vec, style: Option, ) -> SheetBorders { - generate_borders_full(sheet, region, selections, vec![style]) + generate_borders_full(sheet, rect, selections, vec![style]) } pub fn generate_borders_full( sheet: &Sheet, - region: &RegionRef, + rect: &Rect, selections: Vec, styles: Vec>, ) -> SheetBorders { - let mut id_space_borders = sheet.borders.per_cell.clone_region(&sheet.row_ids, region); - let mut render_borders = sheet - .borders - .render_lookup - .clone_rects(&sheet.region_rects(region).collect_vec()); + let mut id_space_borders = sheet.borders.per_cell.clone_rect(rect); + let mut render_borders = sheet.borders.render_lookup.clone_rect(rect); // if Clear then set style to None let styles = if selections.len() == 1 && selections[0] == BorderSelection::Clear { @@ -40,43 +35,27 @@ pub fn generate_borders_full( styles }; - for rect in sheet.region_rects(region) { - for style in styles.iter() { - let horizontal = compute_indices::horizontal(rect, selections.clone()); - let vertical = compute_indices::vertical(rect, selections.clone()); - - for &horizontal_border_index in &horizontal { - let above_index = horizontal_border_index - 1; - let column_ids = rect - .x_range() - .filter_map(|index| sheet.get_column(index)) - .map(|column| column.id) - .collect_vec(); - - id_space_borders.set_horizontal_border(&column_ids, above_index, *style); - render_borders.set_horizontal_border( - horizontal_border_index, - rect.x_range(), - *style, - ); - } + for style in styles.iter() { + let horizontal = compute_indices::horizontal(rect, selections.clone()); + let vertical = compute_indices::vertical(rect, selections.clone()); - for &vertical_border_index in &vertical { - let column_left_index = vertical_border_index - 1; - let column_left_id = sheet.get_column(column_left_index).map(|column| column.id); + for &horizontal_border_index in &horizontal { + let above_index = horizontal_border_index - 1; - let column_right_index = vertical_border_index; - let column_right_id = sheet.get_column(column_right_index).map(|column| column.id); + id_space_borders.set_horizontal_border(rect.x_range(), above_index, *style); + render_borders.set_horizontal_border(horizontal_border_index, rect.x_range(), *style); + } - let row_indices = rect.y_range().collect_vec(); - id_space_borders.set_vertical_border( - column_left_id, - column_right_id, - &row_indices, - *style, - ); - render_borders.set_vertical_border(vertical_border_index, rect.y_range(), *style); - } + for &vertical_border in &vertical { + let column_left = vertical_border - 1; + + id_space_borders.set_vertical_border( + Some(column_left), + Some(vertical_border), + rect.y_range(), + *style, + ); + render_borders.set_vertical_border(vertical_border, rect.y_range(), *style); } } SheetBorders { @@ -85,32 +64,23 @@ pub fn generate_borders_full( } } -pub fn set_region_borders( - sheet: &mut Sheet, - regions: Vec, - borders: SheetBorders, -) -> SheetBorders { - let rects = regions - .iter() - .flat_map(|region| sheet.region_rects(region)) - .collect_vec(); - let current_borders = &mut sheet.borders; - current_borders.set_regions(&sheet.row_ids, regions, rects, borders) +pub fn set_rect_borders(sheet: &mut Sheet, rect: &Rect, borders: SheetBorders) -> SheetBorders { + sheet.borders.set_rect(rect, borders) } #[cfg(test)] -pub fn set_region_border_selection( +pub fn set_rect_border_selection( sheet: &mut Sheet, - region: &RegionRef, + rect: &Rect, selections: Vec, style: Option, ) -> SheetBorders { - let borders = generate_borders(sheet, region, selections, style); - set_region_borders(sheet, vec![region.clone()], borders) + let borders = generate_borders(sheet, rect, selections, style); + set_rect_borders(sheet, rect, borders) } -pub fn get_region_borders(sheet: &Sheet, regions: Vec) -> SheetBorders { - sheet.borders.get_regions(&sheet.row_ids, regions) +pub fn get_rect_borders(sheet: &Sheet, rect: &Rect) -> SheetBorders { + sheet.borders.get_rect(rect) } pub fn get_cell_borders_in_rect(sheet: &Sheet, rect: Rect) -> Vec<(i64, i64, Option)> { @@ -118,11 +88,9 @@ pub fn get_cell_borders_in_rect(sheet: &Sheet, rect: Rect) -> Vec<(i64, i64, Opt let mut id_space_borders = sheet.borders().per_cell.to_owned(); for (i, x) in rect.x_range().enumerate() { - if let Some(column) = sheet.get_column(x) { - for (j, y) in rect.y_range().enumerate() { - let border = id_space_borders.get_cell_border(column.id, y); - borders.push((i as i64, j as i64, border)); - } + for (j, y) in rect.y_range().enumerate() { + let border = id_space_borders.get_cell_border(Pos { x, y }); + borders.push((i as i64, j as i64, border)); } } @@ -140,51 +108,35 @@ impl SheetBorders { Self::default() } - fn set_regions( - &mut self, - row_ids: &IdMap, - regions: Vec, - rects: Vec, - borders: SheetBorders, - ) -> SheetBorders { + fn set_rect(&mut self, rect: &Rect, borders: SheetBorders) -> SheetBorders { let mut previous_borders = SheetBorders::default(); - for region in regions { - let replaced_id_space = - self.per_cell - .replace_region(&borders.per_cell, row_ids, ®ion); - previous_borders - .per_cell - .replace_region(&replaced_id_space, row_ids, ®ion); - } + let replaced_id_space = self.per_cell.replace_rect(&borders.per_cell, rect); + previous_borders + .per_cell + .replace_rect(&replaced_id_space, rect); let replaced_grid_space = self .render_lookup - .replace_rects(&borders.render_lookup, &rects); + .replace_rect(&borders.render_lookup, rect); previous_borders .render_lookup - .replace_rects(&replaced_grid_space, &rects); + .replace_rect(&replaced_grid_space, rect); previous_borders } - fn get_regions(&self, row_ids: &IdMap, regions: Vec) -> SheetBorders { + fn get_rect(&self, rect: &Rect) -> SheetBorders { let mut sheet_borders = SheetBorders::default(); - - for region in regions { - let cloned_id_space = self.per_cell.clone_region(row_ids, ®ion); - sheet_borders - .per_cell - .replace_region(&cloned_id_space, row_ids, ®ion); - } - + let cloned_id_space = self.per_cell.clone_rect(rect); + sheet_borders.per_cell.replace_rect(&cloned_id_space, rect); sheet_borders } } #[derive(Debug, Clone, Default, PartialEq)] pub struct IdSpaceBorders { - pub borders: HashMap>>, + pub borders: HashMap>>, } impl Serialize for IdSpaceBorders { @@ -212,109 +164,114 @@ impl<'de> Deserialize<'de> for IdSpaceBorders { borders: HashMap::new(), }; for (k, v) in map { - ret.borders.insert(ColumnId::from_str(k).unwrap(), v); + ret.borders.insert(k.parse::().unwrap(), v); } Ok(ret) } } impl IdSpaceBorders { - fn clone_region(&self, row_ids: &IdMap, region: &RegionRef) -> Self { + fn clone_rect(&self, rect: &Rect) -> Self { let mut cloned = Self::default(); - cloned.replace_region(self, row_ids, region); + cloned.replace_rect(self, rect); cloned } - fn replace_region( - &mut self, - source: &Self, - row_ids: &IdMap, - region: &RegionRef, - ) -> Self { + fn replace_rect(&mut self, source: &Self, rect: &Rect) -> Self { let mut previous = Self::default(); - for column_id in ®ion.columns { - let row_ranges = grid::sheet::row_ranges(®ion.rows, row_ids); - let replacement = source.clone_blocks(*column_id, row_ranges.clone()); - - let dest_column = self.borders.entry(*column_id).or_default(); - let previous_column = previous.borders.entry(*column_id).or_default(); - - for range in row_ranges { - let replaced = dest_column.clone_range(&replacement, range); - for old_block in replaced { - previous_column.set_range(old_block.range(), old_block.content.value); - } + for x in rect.x_range() { + let replacement = source.clone_blocks(x, rect.y_range().clone()); + let dest_column = self.borders.entry(x).or_default(); + let previous_column = previous.borders.entry(x).or_default(); + + let replaced = dest_column.clone_range(&replacement, rect.y_range()); + for old_block in replaced { + previous_column.set_range(old_block.range(), old_block.content.value); } } previous } - fn clone_blocks( - &self, - column_id: ColumnId, - row_ranges: Vec>, - ) -> ColumnData> { + fn clone_blocks(&self, x: i64, range: Range) -> ColumnData> { let mut column = ColumnData::new(); - if let Some(source_column) = self.borders.get(&column_id) { - for range in row_ranges { - column.clone_range(source_column, range); - } + if let Some(source_column) = self.borders.get(&x) { + column.clone_range(source_column, range); } column } fn set_horizontal_border( &mut self, - columns: &[ColumnId], + columns: Range, row_index_above: i64, style: Option, ) { let row_index_below = row_index_above + 1; - for &column_id in columns { - self.set_cell_border(column_id, row_index_above, CellSide::Bottom, style); - self.set_cell_border(column_id, row_index_below, CellSide::Top, style); + for x in columns { + self.set_cell_border( + Pos { + x, + y: row_index_above, + }, + CellSide::Bottom, + style, + ); + self.set_cell_border( + Pos { + x, + y: row_index_below, + }, + CellSide::Top, + style, + ); } } fn set_vertical_border( &mut self, - column_left: Option, - column_right: Option, - row_indices: &[i64], + column_left: Option, + column_right: Option, + rows: Range, style: Option, ) { - for &row_index in row_indices { + for row_index in rows { if let Some(column_left) = column_left { - self.set_cell_border(column_left, row_index, CellSide::Right, style); + self.set_cell_border( + Pos { + x: column_left, + y: row_index, + }, + CellSide::Right, + style, + ); } if let Some(column_right) = column_right { - self.set_cell_border(column_right, row_index, CellSide::Left, style); + self.set_cell_border( + Pos { + x: column_right, + y: row_index, + }, + CellSide::Left, + style, + ); } } } - pub fn set_cell_border( - &mut self, - column_id: ColumnId, - row_index: i64, - side: CellSide, - style: Option, - ) { - // TODO(jrice): Iterative `set` is broken. Need to use `set_range` - let column_borders = self.borders.entry(column_id).or_default(); - - let new_borders = CellBorders::combine(column_borders.get(row_index), side, style); + pub fn set_cell_border(&mut self, pos: Pos, side: CellSide, style: Option) { + let column_borders = self.borders.entry(pos.x).or_default(); + let new_borders = CellBorders::combine(column_borders.get(pos.y), side, style); if new_borders.is_empty() { - column_borders.set(row_index, None); + column_borders.set(pos.y, None); } else { - column_borders.set(row_index, Some(new_borders)); + column_borders.set(pos.y, Some(new_borders)); } } - pub fn get_cell_border(&mut self, column_id: ColumnId, row_index: i64) -> Option { - let column_borders = self.borders.entry(column_id).or_default(); - column_borders.get(row_index) + pub fn get_cell_border(&mut self, pos: Pos) -> Option { + let column_borders = self.borders.entry(pos.x).or_default(); + column_borders.get(pos.y) } } @@ -325,39 +282,37 @@ pub struct GridSpaceBorders { } impl GridSpaceBorders { - fn clone_rects(&self, rects: &[Rect]) -> GridSpaceBorders { + fn clone_rect(&self, rect: &Rect) -> GridSpaceBorders { let mut cloned = Self::default(); - cloned.replace_rects(self, rects); + cloned.replace_rect(self, rect); cloned } - fn replace_rects(&mut self, source: &Self, rects: &[Rect]) -> Self { + fn replace_rect(&mut self, source: &Self, rect: &Rect) -> Self { let mut previous = Self::default(); - for rect in rects { - // Vertical borders - for x in rect.x_range().chain([rect.x_range().end]) { - if let Some(source_column) = source.vertical.get(&x) { - let current_column = self.vertical.entry(x).or_default(); - let previous_column = previous.vertical.entry(x).or_default(); - - let replaced_styles = current_column.clone_range(source_column, rect.y_range()); - for old_style in replaced_styles { - previous_column.set_range(old_style.range(), old_style.content.value); - } + // Vertical borders + for x in rect.x_range().chain([rect.x_range().end]) { + if let Some(source_column) = source.vertical.get(&x) { + let current_column = self.vertical.entry(x).or_default(); + let previous_column = previous.vertical.entry(x).or_default(); + + let replaced_styles = current_column.clone_range(source_column, rect.y_range()); + for old_style in replaced_styles { + previous_column.set_range(old_style.range(), old_style.content.value); } } + } - // Horizontal - for y in rect.y_range().chain([rect.y_range().end]) { - if let Some(source_column) = source.horizontal.get(&y) { - let current_column = self.horizontal.entry(y).or_default(); - let previous_column = previous.horizontal.entry(y).or_default(); + // Horizontal + for y in rect.y_range().chain([rect.y_range().end]) { + if let Some(source_column) = source.horizontal.get(&y) { + let current_column = self.horizontal.entry(y).or_default(); + let previous_column = previous.horizontal.entry(y).or_default(); - let replaced_styles = current_column.clone_range(source_column, rect.x_range()); - for old_style in replaced_styles { - previous_column.set_range(old_style.range(), old_style.content.value); - } + let replaced_styles = current_column.clone_range(source_column, rect.x_range()); + for old_style in replaced_styles { + previous_column.set_range(old_style.range(), old_style.content.value); } } } @@ -395,62 +350,37 @@ pub mod debug { use super::*; pub trait GetCellBorders { - fn get_cell_borders( - &self, - pos: Pos, - column_ids: &IdMap, - ) -> Option; + fn get_cell_borders(&self, pos: Pos) -> Option; } impl GetCellBorders for SheetBorders { - fn get_cell_borders( - &self, - pos: Pos, - column_ids: &IdMap, - ) -> Option { - self.per_cell.get_cell_borders(pos, column_ids) + fn get_cell_borders(&self, pos: Pos) -> Option { + self.per_cell.get_cell_borders(pos) } } impl GetCellBorders for IdSpaceBorders { - fn get_cell_borders( - &self, - pos: Pos, - column_ids: &IdMap, - ) -> Option { - if let Some(column_id) = column_ids.id_at(pos.x) { - let column = self.borders.get(&column_id); - column.and_then(|column| column.get(pos.y)) - } else { - None - } + fn get_cell_borders(&self, pos: Pos) -> Option { + let column = self.borders.get(&pos.x); + column.and_then(|column| column.get(pos.y)) } } - pub fn print_borders( - rect: Rect, - sheet_borders: &T, - column_ids: &IdMap, - ) { + pub fn print_borders(rect: Rect, sheet_borders: &T) { for row in rect.y_range() { - print_tops(rect, sheet_borders, column_ids, row); + print_tops(rect, sheet_borders, row); println!(); - print_middles(rect, sheet_borders, column_ids, row); + print_middles(rect, sheet_borders, row); println!(); - print_bottoms(rect, sheet_borders, column_ids, row); + print_bottoms(rect, sheet_borders, row); println!(); } } - fn print_tops( - rect: Rect, - sheet_borders: &T, - column_ids: &IdMap, - row: i64, - ) { + fn print_tops(rect: Rect, sheet_borders: &T, row: i64) { for col in rect.x_range() { let pos = Pos { x: col, y: row }; - let borders = sheet_borders.get_cell_borders(pos, column_ids); + let borders = sheet_borders.get_cell_borders(pos); if borders.is_some_and(|borders| borders.contains(&CellSide::Top)) { print!(" _____ "); } else { @@ -459,15 +389,10 @@ pub mod debug { } } - fn print_middles( - rect: Rect, - sheet_borders: &T, - column_ids: &IdMap, - row: i64, - ) { + fn print_middles(rect: Rect, sheet_borders: &T, row: i64) { for col in rect.x_range() { let pos = Pos { x: col, y: row }; - let borders = sheet_borders.get_cell_borders(pos, column_ids); + let borders = sheet_borders.get_cell_borders(pos); if borders.is_some_and(|borders| borders.contains(&CellSide::Left)) { print!("|"); } else { @@ -482,15 +407,10 @@ pub mod debug { } } - fn print_bottoms( - rect: Rect, - sheet_borders: &T, - column_ids: &IdMap, - row: i64, - ) { + fn print_bottoms(rect: Rect, sheet_borders: &T, row: i64) { for col in rect.x_range() { let pos = Pos { x: col, y: row }; - let borders = sheet_borders.get_cell_borders(pos, column_ids); + let borders = sheet_borders.get_cell_borders(pos); if borders.is_some_and(|borders| borders.contains(&CellSide::Bottom)) { print!(" ————— "); } else { @@ -514,12 +434,12 @@ mod tests { /// Convenience for asserting expected borders more tersely macro_rules! assert_borders { ($sheet_borders: expr, $column_ids: expr, $cell: expr, None, $message: literal) => { - let actual = $sheet_borders.get_cell_borders($cell, &$column_ids); + let actual = $sheet_borders.get_cell_borders($cell); let expected = None; assert_eq!(actual, expected, $message); }; ($sheet_borders: expr, $column_ids: expr, $cell: expr, $borders: tt, $message: literal) => { - let actual = $sheet_borders.get_cell_borders($cell, &$column_ids); + let actual = $sheet_borders.get_cell_borders($cell); let expected = Some(CellBorders::new(&$borders)); assert_eq!(actual, expected, $message); }; @@ -529,7 +449,7 @@ mod tests { macro_rules! assert_borders_eq { ($sheet_borders: expr, $column_ids: expr, $cell_borders: tt, $message: literal) => { for (cell, expected_borders) in &$cell_borders { - let actual = $sheet_borders.get_cell_borders(*cell, &$column_ids); + let actual = $sheet_borders.get_cell_borders(*cell); let expected = Some(CellBorders::new(&(*expected_borders))); assert_eq!(actual, expected, $message); } @@ -541,7 +461,6 @@ mod tests { fn all_borders() { let mut sheet = Sheet::new(SheetId::new(), "Test Sheet".to_string(), "".to_string()); let rect = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 6, y: 15 }); - let region = sheet.region(rect); let selection = vec![BorderSelection::All]; @@ -550,8 +469,7 @@ mod tests { line: CellBorderLine::Line1, }; - let _prev_borders = - set_region_border_selection(&mut sheet, ®ion, selection, Some(style)); + let _prev_borders = set_rect_border_selection(&mut sheet, &rect, selection, Some(style)); assert_borders!( sheet.borders, @@ -603,7 +521,6 @@ mod tests { fn outer_borders() { let mut sheet = Sheet::new(SheetId::new(), "Test Sheet".to_string(), "".to_string()); let rect = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 5, y: 12 }); - let region = sheet.region(rect); let selection = vec![BorderSelection::Outer]; @@ -612,8 +529,7 @@ mod tests { line: CellBorderLine::Line1, }; - let _prev_borders = - set_region_border_selection(&mut sheet, ®ion, selection, Some(style)); + let _prev_borders = set_rect_border_selection(&mut sheet, &rect, selection, Some(style)); assert_borders!( sheet.borders, @@ -639,9 +555,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 5, y: 12 }); let rect_2 = Rect::new_span(Pos { x: 4, y: 11 }, Pos { x: 6, y: 13 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = vec![BorderSelection::All]; @@ -651,9 +564,9 @@ mod tests { }; let _prev_borders_1 = - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style)); - let _prev_borders_2 = set_region_border_selection(&mut sheet, ®ion_2, selection_2, None); + let _prev_borders_2 = set_rect_border_selection(&mut sheet, &rect_2, selection_2, None); assert_borders!( sheet.borders, @@ -697,9 +610,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 5, y: 12 }); let rect_2 = Rect::new_span(Pos { x: 4, y: 11 }, Pos { x: 6, y: 13 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = vec![BorderSelection::All]; @@ -709,8 +619,8 @@ mod tests { }; let _prev_borders_1 = - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style)); - let prev_borders_2 = set_region_border_selection(&mut sheet, ®ion_2, selection_2, None); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style)); + let prev_borders_2 = set_rect_border_selection(&mut sheet, &rect_2, selection_2, None); let expected_cell_borders = [ (CellSide::Left, style), @@ -739,9 +649,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 5, y: 12 }); let rect_2 = Rect::new_span(Pos { x: 4, y: 11 }, Pos { x: 6, y: 13 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = vec![BorderSelection::Horizontal]; @@ -755,10 +662,10 @@ mod tests { }; let _prev_borders_1 = - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style_1)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style_1)); let _prev_borders_2 = - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style_2)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style_2)); assert_borders!( sheet.borders, @@ -815,9 +722,6 @@ mod tests { let rect_1 = Rect::new_span(Pos { x: 3, y: 10 }, Pos { x: 5, y: 12 }); let rect_2 = Rect::new_span(Pos { x: 4, y: 11 }, Pos { x: 6, y: 13 }); - let region_1 = sheet.region(rect_1); - let region_2 = sheet.region(rect_2); - let selection_1 = vec![BorderSelection::All]; let selection_2 = vec![BorderSelection::Horizontal]; @@ -831,9 +735,9 @@ mod tests { }; let _prev_borders_1 = - set_region_border_selection(&mut sheet, ®ion_1, selection_1, Some(style_1)); + set_rect_border_selection(&mut sheet, &rect_1, selection_1, Some(style_1)); let prev_borders_2 = - set_region_border_selection(&mut sheet, ®ion_2, selection_2, Some(style_2)); + set_rect_border_selection(&mut sheet, &rect_2, selection_2, Some(style_2)); let expected_cell_borders = [ (CellSide::Left, style_1), diff --git a/quadratic-core/src/grid/code.rs b/quadratic-core/src/grid/code.rs index 11a24391d2..337e492b4f 100644 --- a/quadratic-core/src/grid/code.rs +++ b/quadratic-core/src/grid/code.rs @@ -1,9 +1,10 @@ +use std::collections::HashSet; + use serde::{Deserialize, Serialize}; use strum_macros::{Display, EnumString}; use wasm_bindgen::prelude::wasm_bindgen; -use super::CellRef; -use crate::{ArraySize, CellValue, Error, Rect, Value}; +use crate::{ArraySize, CellValue, Error, Rect, SheetPos, Value}; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct CodeCellValue { @@ -57,7 +58,7 @@ impl CodeCellValue { self.output.as_ref().map(|out| out.spill).unwrap_or(false) } - pub fn cells_accessed_copy(&self) -> Option> { + pub fn cells_accessed_copy(&self) -> Option> { self.output.as_ref()?.cells_accessed().cloned() } @@ -98,7 +99,7 @@ impl CodeCellRunOutput { self.result.output_value() } - pub fn cells_accessed(&self) -> Option<&Vec> { + pub fn cells_accessed(&self) -> Option<&HashSet> { match &self.result { CodeCellRunResult::Ok { cells_accessed, .. } => Some(cells_accessed), CodeCellRunResult::Err { .. } => None, @@ -111,7 +112,7 @@ impl CodeCellRunOutput { pub enum CodeCellRunResult { Ok { output_value: Value, - cells_accessed: Vec, + cells_accessed: HashSet, }, Err { error: Error, @@ -137,10 +138,8 @@ impl CodeCellRunResult { #[cfg(test)] mod test { - use crate::{ - grid::{CodeCellRunOutput, CodeCellValue}, - Array, ArraySize, Pos, Rect, - }; + use super::*; + use crate::{Array, Pos}; #[test] fn test_output_size() { @@ -166,7 +165,7 @@ mod test { output_value: crate::Value::Array(Array::new_empty( ArraySize::new(10, 11).unwrap(), )), - cells_accessed: vec![], + cells_accessed: HashSet::new(), }, spill: false, }), diff --git a/quadratic-core/src/grid/column.rs b/quadratic-core/src/grid/column.rs index 12b9798987..ad24f7ae13 100644 --- a/quadratic-core/src/grid/column.rs +++ b/quadratic-core/src/grid/column.rs @@ -9,15 +9,15 @@ use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; use super::formatting::*; -use super::{Block, BlockContent, CellRef, CellValueBlockContent, ColumnId, SameValue}; -use crate::IsBlank; +use super::{Block, BlockContent, CellValueBlockContent, SameValue}; +use crate::{IsBlank, Pos}; -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq)] pub struct Column { - pub id: ColumnId, + pub x: i64, pub values: ColumnData, - pub spills: ColumnData>, + pub spills: ColumnData>, pub align: ColumnData>, pub wrap: ColumnData>, @@ -31,26 +31,10 @@ pub struct Column { pub render_size: ColumnData>, } impl Column { - pub fn new() -> Self { - Column::with_id(ColumnId::new()) - } - pub fn with_id(id: ColumnId) -> Self { - Column { - id, - - values: ColumnData::default(), - spills: ColumnData::default(), - - align: ColumnData::default(), - wrap: ColumnData::default(), - numeric_format: ColumnData::default(), - numeric_decimals: ColumnData::default(), - numeric_commas: ColumnData::default(), - bold: ColumnData::default(), - italic: ColumnData::default(), - text_color: ColumnData::default(), - fill_color: ColumnData::default(), - render_size: ColumnData::default(), + pub fn new(x: i64) -> Self { + Self { + x, + ..Default::default() } } @@ -89,12 +73,6 @@ impl Column { } } -impl Default for Column { - fn default() -> Self { - Self::new() - } -} - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct ColumnData Deserialize<'d>>( #[serde(with = "crate::util::btreemap_serde")] BTreeMap>, diff --git a/quadratic-core/src/grid/file/current.rs b/quadratic-core/src/grid/file/current.rs index da70be4aa0..0b66c1bb0f 100644 --- a/quadratic-core/src/grid/file/current.rs +++ b/quadratic-core/src/grid/file/current.rs @@ -1,16 +1,15 @@ use crate::color::Rgba; use crate::grid::formatting::RenderSize; use crate::grid::{ - generate_borders, set_region_borders, BorderSelection, BorderStyle, CellAlign, CellBorderLine, - CellWrap, Grid, GridBounds, NumericFormat, NumericFormatKind, RegionRef, + generate_borders, set_rect_borders, BorderSelection, BorderStyle, CellAlign, CellBorderLine, + CellWrap, Grid, GridBounds, NumericFormat, NumericFormatKind, }; -use crate::{CellValue, Error, ErrorMsg, Span, Value}; +use crate::{CellValue, Error, ErrorMsg, Pos, Rect, SheetPos, Span, Value}; -use crate::grid::file::v1_4::schema::{self as current}; +use crate::grid::file::v1_5::schema::{self as current}; use crate::grid::{ - block::SameValue, sheet::sheet_offsets::SheetOffsets, CellRef, CodeCellLanguage, - CodeCellRunOutput, CodeCellRunResult, CodeCellValue, Column, ColumnData, ColumnId, RowId, - Sheet, SheetBorders, SheetId, + block::SameValue, sheet::sheet_offsets::SheetOffsets, CodeCellLanguage, CodeCellRunOutput, + CodeCellRunResult, CodeCellValue, Column, ColumnData, Sheet, SheetBorders, SheetId, }; use anyhow::{anyhow, Result}; use bigdecimal::BigDecimal; @@ -23,21 +22,6 @@ use std::{ }; use super::CURRENT_VERSION; -impl From for current::CellRef { - fn from(cell_ref: CellRef) -> Self { - Self { - sheet: current::Id { - id: cell_ref.sheet.to_string(), - }, - column: current::Id { - id: cell_ref.column.to_string(), - }, - row: current::Id { - id: cell_ref.row.to_string(), - }, - } - } -} fn set_column_format( column_data: &mut ColumnData>, @@ -135,12 +119,9 @@ fn set_column_format_render_size( fn import_column_builder(columns: &[(i64, current::Column)]) -> Result> { columns .iter() - .map(|(y, column)| { - let mut col = Column { - id: ColumnId::from_str(&column.id.id)?, - ..Default::default() - }; - set_column_format::(&mut col.spills, &column.spills)?; + .map(|(x, column)| { + let mut col = Column::new(*x); + set_column_format::(&mut col.spills, &column.spills)?; set_column_format::(&mut col.align, &column.align)?; set_column_format::(&mut col.wrap, &column.wrap)?; set_column_format_i16(&mut col.numeric_decimals, &column.numeric_decimals)?; @@ -172,54 +153,44 @@ fn import_column_builder(columns: &[(i64, current::Column)]) -> Result>>() } fn import_borders_builder(sheet: &mut Sheet, current_sheet: &mut current::Sheet) { - current_sheet - .borders - .iter() - .for_each(|(column_id, cell_borders)| { - cell_borders.iter().for_each(|(y, cell_borders)| { - cell_borders.iter().enumerate().for_each(|(index, border)| { - if let Some(border) = border { - let border_selection = match index { - 0 => BorderSelection::Left, - 1 => BorderSelection::Top, - 2 => BorderSelection::Right, - 3 => BorderSelection::Bottom, - _ => BorderSelection::Clear, - }; - let style = BorderStyle { - color: Rgba::from_str(&border.color) - .unwrap_or_else(|_| Rgba::new(0, 0, 0, 255)), - line: CellBorderLine::from_str(&border.line) - .unwrap_or(CellBorderLine::Line1), - }; - - if let Ok(column_id) = ColumnId::from_str(column_id) { - let row_id = sheet.get_or_create_row(*y); - let region = RegionRef { - sheet: sheet.id, - columns: vec![column_id], - rows: vec![row_id.id], - }; - let borders = generate_borders( - sheet, - ®ion, - vec![border_selection], - Some(style), - ); + current_sheet.borders.iter().for_each(|(x, cell_borders)| { + cell_borders.iter().for_each(|(y, cell_borders)| { + cell_borders.iter().enumerate().for_each(|(index, border)| { + if let Some(border) = border { + let border_selection = match index { + 0 => BorderSelection::Left, + 1 => BorderSelection::Top, + 2 => BorderSelection::Right, + 3 => BorderSelection::Bottom, + _ => BorderSelection::Clear, + }; + let style = BorderStyle { + color: Rgba::from_str(&border.color) + .unwrap_or_else(|_| Rgba::new(0, 0, 0, 255)), + line: CellBorderLine::from_str(&border.line) + .unwrap_or(CellBorderLine::Line1), + }; - // necessary to fill in render_lookup in SheetBorders - set_region_borders(sheet, vec![region], borders); - } - } - }); + // todo: this should save as an i64, not string + let rect = Rect::single_pos(Pos { + x: x.parse::().unwrap(), + y: *y, + }); + let borders = + generate_borders(sheet, &rect, vec![border_selection], Some(style)); + + // necessary to fill in render_lookup in SheetBorders + set_rect_borders(sheet, &rect, borders); + } }); }); + }); } fn import_code_cell_output(type_field: &str, value: &str) -> CellValue { @@ -231,17 +202,13 @@ fn import_code_cell_output(type_field: &str, value: &str) -> CellValue { } } -fn import_code_cell_builder(sheet: ¤t::Sheet) -> Result> { +fn import_code_cell_builder(sheet: ¤t::Sheet) -> Result> { sheet .code_cells .iter() - .map(|(cell_ref, code_cell_value)| { + .map(|(pos, code_cell_value)| { Ok(( - CellRef { - sheet: SheetId::from_str(&cell_ref.sheet.id)?, - column: ColumnId::from_str(&cell_ref.column.id)?, - row: RowId::from_str(&cell_ref.row.id)?, - }, + Pos { x: pos.x, y: pos.y }, CodeCellValue { language: CodeCellLanguage::from_str(&code_cell_value.language)?, code_string: code_cell_value.code_string.to_owned(), @@ -286,10 +253,10 @@ fn import_code_cell_builder(sheet: ¤t::Sheet) -> Result>() @@ -327,16 +294,6 @@ pub fn import(file: current::GridSchema) -> Result { name: sheet.name.to_owned(), color: sheet.color.to_owned(), order: sheet.order.to_owned(), - column_ids: sheet - .columns - .iter() - .map(|(x, column)| Ok((*x, ColumnId::from_str(&column.id.id)?))) - .collect::>()?, - row_ids: sheet - .rows - .iter() - .map(|(x, row)| Ok((*x, RowId::from_str(&row.id)?))) - .collect::>()?, offsets: SheetOffsets::import(&sheet.offsets), columns: import_column_builder(&sheet.columns)?, // borders set after sheet is loaded @@ -445,14 +402,13 @@ where fn export_column_builder(sheet: &Sheet) -> Vec<(i64, current::Column)> { sheet - .iter_columns() + .columns + .iter() .map(|(x, column)| { ( - x, + *x, current::Column { - id: current::Id { - id: column.id.to_string(), - }, + x: *x, spills: export_column_data(&column.spills), align: export_column_data(&column.align), wrap: export_column_data(&column.wrap), @@ -493,9 +449,10 @@ fn export_borders_builder(sheet: &Sheet) -> current::Borders { .per_cell .borders .iter() - .map(|(column_id, border)| { + .map(|(x, border)| { ( - column_id.to_string(), + // todo: this should be i64 + x.to_string(), border .values() .map(|(y, cell_borders)| { @@ -536,24 +493,13 @@ pub fn export(grid: &mut Grid) -> Result { order: sheet.order.to_owned(), offsets: sheet.offsets.export(), columns: export_column_builder(sheet), - rows: sheet - .iter_rows() - .map(|(x, row_id)| { - ( - x, - current::Id { - id: row_id.to_string(), - }, - ) - }) - .collect(), borders: export_borders_builder(sheet), code_cells: sheet .iter_code_cells_locations() - .map(|cell_ref| { - let code_cell_value = sheet.get_code_cell_from_ref(cell_ref).unwrap().clone(); + .map(|pos| { + let code_cell_value = sheet.get_code_cell(pos).unwrap().clone(); ( - cell_ref.into(), + pos.into(), current::CodeCellValue { language: code_cell_value.language.to_string(), code_string: code_cell_value.code_string, @@ -631,13 +577,13 @@ pub fn export(grid: &mut Grid) -> Result { mod tests { use super::*; - const V1_4_FILE: &str = include_str!("../../../examples/v1_4_simple.grid"); + const V1_5_FILE: &str = include_str!("../../../../rust-shared/data/grid/v1_5_simple.grid"); #[test] fn imports_and_exports_a_current_grid() { - let file = serde_json::from_str::(V1_4_FILE).unwrap(); + let file = serde_json::from_str::(V1_5_FILE).unwrap(); let mut imported = import(file).unwrap(); - let exported = export(&mut imported).unwrap(); - println!("{:?}", exported); + let _exported = export(&mut imported).unwrap(); + // println!("{:?}", exported); } } diff --git a/quadratic-core/src/grid/file/mod.rs b/quadratic-core/src/grid/file/mod.rs index 08e0c9e23e..dd1f6e0a7b 100644 --- a/quadratic-core/src/grid/file/mod.rs +++ b/quadratic-core/src/grid/file/mod.rs @@ -7,12 +7,18 @@ use super::Grid; pub mod current; mod v1_3; mod v1_4; +mod v1_5; -pub static CURRENT_VERSION: &str = "1.4"; +pub static CURRENT_VERSION: &str = "1.5"; #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "version")] enum GridFile { + #[serde(rename = "1.5")] + V1_5 { + #[serde(flatten)] + grid: v1_5::schema::GridSchema, + }, #[serde(rename = "1.4")] V1_4 { #[serde(flatten)] @@ -26,10 +32,19 @@ enum GridFile { } impl GridFile { - fn into_latest(self) -> Result { + fn into_latest(self) -> Result { match self { - GridFile::V1_4 { grid } => Ok(grid), - GridFile::V1_3 { grid } => v1_3::file::upgrade(grid), + GridFile::V1_5 { grid } => Ok(grid), + GridFile::V1_4 { grid } => v1_4::file::upgrade(grid), + GridFile::V1_3 { grid } => { + if let Ok(v1_4) = v1_3::file::upgrade(grid) { + v1_4::file::upgrade(v1_4) + } else { + Err(anyhow!( + "Failed to upgrade from v1.3 to v1.4 (on the way to v1.5" + )) + } + } } } } @@ -57,23 +72,24 @@ mod tests { use super::*; use crate::{ color::Rgba, - grid::{ - generate_borders, set_region_borders, BorderSelection, BorderStyle, CellBorderLine, - }, + grid::{generate_borders, set_rect_borders, BorderSelection, BorderStyle, CellBorderLine}, Pos, Rect, }; - const V1_3_FILE: &str = include_str!("../../../examples/v1_3.grid"); - const V1_3_PYTHON_FILE: &str = include_str!("../../../examples/v1_3_python.grid"); + const V1_3_FILE: &str = include_str!("../../../../rust-shared/data/grid/v1_3.grid"); + const V1_3_PYTHON_FILE: &str = + include_str!("../../../../rust-shared/data/grid/v1_3_python.grid"); const V1_3_TEXT_ONLY_CODE_CELL_FILE: &str = - include_str!("../../../examples/c1_3_python_text_only.grid"); + include_str!("../../../../rust-shared/data/grid/v1_3_python_text_only.grid"); const V1_3_SINGLE_FORMULS_CODE_CELL_FILE: &str = - include_str!("../../../examples/v1_3_single_formula.grid"); - const V1_3_NPM_DOWNLOADS_FILE: &str = include_str!("../../../examples/v1_3_fill_color.grid"); - const V1_3_BORDERS_FILE: &str = include_str!("../../../examples/v1_3_borders.grid"); - const V1_4_FILE: &str = include_str!("../../../examples/v1_4_simple.grid"); + include_str!("../../../../rust-shared/data/grid/v1_3_single_formula.grid"); + const V1_3_NPM_DOWNLOADS_FILE: &str = + include_str!("../../../../rust-shared/data/grid/v1_3_fill_color.grid"); + const V1_3_BORDERS_FILE: &str = + include_str!("../../../../rust-shared/data/grid/v1_3_borders.grid"); + const V1_4_FILE: &str = include_str!("../../../../rust-shared/data/grid/v1_4_simple.grid"); const V1_4_AIRPORTS_DISTANCE_FILE: &str = - include_str!("../../../examples/v1_4_airports_distance.grid"); + include_str!("../../../../rust-shared/data/grid/v1_4_airports_distance.grid"); #[test] fn process_a_v1_3_file() { @@ -147,14 +163,13 @@ mod tests { let mut grid = Grid::new(); let sheets = grid.sheets_mut(); let rect = Rect::new_span(Pos { x: 0, y: 0 }, Pos { x: 0, y: 0 }); - let region = sheets[0].region(rect); let selection = vec![BorderSelection::Bottom]; let style = BorderStyle { color: Rgba::from_str("#000000").unwrap(), line: CellBorderLine::Line1, }; - let borders = generate_borders(&sheets[0], ®ion, selection, Some(style)); - set_region_borders(&mut sheets[0], vec![region.clone()], borders); + let borders = generate_borders(&sheets[0], &rect, selection, Some(style)); + set_rect_borders(&mut sheets[0], &rect, borders); // println!("{:#?}", sheets[0].borders); let _exported = export(&mut grid).unwrap(); diff --git a/quadratic-core/src/grid/file/v1_3/file.rs b/quadratic-core/src/grid/file/v1_3/file.rs index d449039fa2..265171243a 100644 --- a/quadratic-core/src/grid/file/v1_3/file.rs +++ b/quadratic-core/src/grid/file/v1_3/file.rs @@ -7,12 +7,12 @@ use std::vec; use super::schema::{Any, ArrayOutput, Cell}; use crate::color::Rgba; use crate::grid::file::v1_3::schema::GridSchema; -use crate::grid::file::v1_4::schema as current; +use crate::grid::file::v1_4::schema as v1_4; -pub(crate) fn upgrade(schema: GridSchema) -> Result { +pub(crate) fn upgrade(schema: GridSchema) -> Result { let sheet = upgrade_sheet(schema)?; - let converted = current::GridSchema { + let converted = v1_4::GridSchema { version: Some("1.4".into()), sheets: vec![sheet], }; @@ -30,7 +30,7 @@ pub fn language_conversion(language: &str) -> String { } } -impl From for current::OutputValueValue { +impl From for v1_4::OutputValueValue { fn from(val: Any) -> Self { match val { Any::Number(n) => match BigDecimal::from_str(n.to_string().as_str()).ok() { @@ -62,31 +62,31 @@ impl From for current::OutputValueValue { } struct SheetBuilder { - sheet_id: current::Id, - columns: HashMap, - column_ids: HashMap, - row_ids: HashMap, - borders: current::Borders, + sheet_id: v1_4::Id, + columns: HashMap, + column_ids: HashMap, + row_ids: HashMap, + borders: v1_4::Borders, } #[allow(clippy::unwrap_or_default)] impl SheetBuilder { - fn column_id(&mut self, x: i64) -> &mut current::Id { - self.column_ids.entry(x).or_insert_with(current::Id::new) + fn column_id(&mut self, x: i64) -> &mut v1_4::Id { + self.column_ids.entry(x).or_insert_with(v1_4::Id::new) } - fn row_id(&mut self, x: i64) -> &mut current::Id { - self.row_ids.entry(x).or_insert_with(current::Id::new) + fn row_id(&mut self, x: i64) -> &mut v1_4::Id { + self.row_ids.entry(x).or_insert_with(v1_4::Id::new) } - fn column(&mut self, x: i64) -> &mut current::Column { + fn column(&mut self, x: i64) -> &mut v1_4::Column { let id = self.column_id(x).to_owned(); self.columns .entry(x) - .or_insert_with(|| current::Column::with_id(id)) + .or_insert_with(|| v1_4::Column::with_id(id)) } - fn cell_ref(&mut self, (x, y): (i64, i64)) -> current::CellRef { - current::CellRef { + fn cell_ref(&mut self, (x, y): (i64, i64)) -> v1_4::CellRef { + v1_4::CellRef { sheet: self.sheet_id.to_owned(), column: self.column_id(x).to_owned(), row: self.row_id(y).to_owned(), @@ -106,7 +106,7 @@ impl SheetBuilder { y.to_string(), ( y, - current::ColumnValue { + v1_4::ColumnValue { type_field: type_field.into(), value: value.to_owned(), }, @@ -116,11 +116,7 @@ impl SheetBuilder { } } - fn code_cell_value( - &mut self, - cell: &Cell, - cell_ref: current::CellRef, - ) -> current::CodeCellValue { + fn code_cell_value(&mut self, cell: &Cell, cell_ref: v1_4::CellRef) -> v1_4::CodeCellValue { let default = String::new(); let language = language_conversion(&cell.type_field); let code_string = match cell.type_field.to_lowercase().as_str() { @@ -135,7 +131,7 @@ impl SheetBuilder { .as_ref() .map(|result| result.formatted_code.to_string()); - current::CodeCellValue { + v1_4::CodeCellValue { language, code_string: code_string.to_string(), formatted_code_string, @@ -143,7 +139,7 @@ impl SheetBuilder { output: cell.evaluation_result.to_owned().and_then(|result| { let column = self.column(cell.x); let code_cell_result = match result.success { - true => current::CodeCellRunResult::Ok { + true => v1_4::CodeCellRunResult::Ok { output_value: if let Some(array) = result.array_output { match array { ArrayOutput::Array(values) => { @@ -154,8 +150,8 @@ impl SheetBuilder { .spills .insert(y.to_string(), (y, cell_ref.to_owned()).into()); } - current::OutputValue::Array(current::OutputArray { - size: current::OutputSize { + v1_4::OutputValue::Array(v1_4::OutputArray { + size: v1_4::OutputSize { w: 1_i64, h: values.len() as i64, }, @@ -186,8 +182,8 @@ impl SheetBuilder { ); } } - current::OutputValue::Array(current::OutputArray { - size: current::OutputSize { + v1_4::OutputValue::Array(v1_4::OutputArray { + size: v1_4::OutputSize { w: values.get(0)?.len() as i64, h: values.len() as i64, }, @@ -203,12 +199,12 @@ impl SheetBuilder { column .spills .insert(cell.y.to_string(), (cell.y, cell_ref.to_owned()).into()); - current::OutputValue::Single(current::OutputValueValue { + v1_4::OutputValue::Single(v1_4::OutputValueValue { type_field: "TEXT".into(), value, }) } else { - current::OutputValue::Single(current::OutputValueValue { + v1_4::OutputValue::Single(v1_4::OutputValueValue { type_field: "BLANK".into(), value: "".into(), }) @@ -219,17 +215,17 @@ impl SheetBuilder { .map(|&(x, y)| self.cell_ref((x, y))) .collect(), }, - false => current::CodeCellRunResult::Err { - error: current::Error { + false => v1_4::CodeCellRunResult::Err { + error: v1_4::Error { span: result .error_span - .map(|(start, end)| current::Span { start, end }), + .map(|(start, end)| v1_4::Span { start, end }), msg: "unknown error".into(), }, }, }; - Some(current::CodeCellRunOutput { + Some(v1_4::CodeCellRunOutput { std_out: result.std_out, std_err: result.std_err, result: code_cell_result, @@ -240,8 +236,8 @@ impl SheetBuilder { } } -pub(crate) fn upgrade_sheet(v: GridSchema) -> Result { - let sheet_id = current::Id::new(); +pub(crate) fn upgrade_sheet(v: GridSchema) -> Result { + let sheet_id = v1_4::Id::new(); let column_widths = v .columns .iter() @@ -309,7 +305,7 @@ pub(crate) fn upgrade_sheet(v: GridSchema) -> Result { if let Some(text_format) = format.text_format { column.numeric_format.insert( format.y.to_string(), - current::NumericFormat { + v1_4::NumericFormat { kind: text_format.type_field, symbol: text_format.symbol.map(|symbol| match symbol.as_ref() { "USD" => "$".into(), @@ -330,13 +326,13 @@ pub(crate) fn upgrade_sheet(v: GridSchema) -> Result { for border in v.borders { let column = sheet.column(border.x); let column_id = column.id.to_string(); - let top = border.horizontal.map(|horizontal| current::CellBorder { + let top = border.horizontal.map(|horizontal| v1_4::CellBorder { color: Rgba::from_css_str(&horizontal.color.unwrap_or("rgb(0, 0, 0)".into())) .unwrap_or_default() .as_string(), line: horizontal.border_type.unwrap_or("line1".into()), }); - let left = border.vertical.map(|vertical| current::CellBorder { + let left = border.vertical.map(|vertical| v1_4::CellBorder { color: Rgba::from_css_str(&vertical.color.unwrap_or("rgb(0, 0, 0)".into())) .unwrap_or_default() .as_string(), @@ -353,7 +349,7 @@ pub(crate) fn upgrade_sheet(v: GridSchema) -> Result { .or_insert(vec![entry]); } - Ok(current::Sheet { + Ok(v1_4::Sheet { id: sheet_id, name: "Sheet 1".into(), color: None, @@ -367,7 +363,7 @@ pub(crate) fn upgrade_sheet(v: GridSchema) -> Result { rows: sheet .row_ids .into_iter() - .map(|(id, row_id)| (id, current::Id { id: row_id.id })) + .map(|(id, row_id)| (id, v1_4::Id { id: row_id.id })) .collect(), borders: sheet.borders, code_cells, @@ -379,7 +375,7 @@ mod tests { use super::*; use anyhow::anyhow; - const V1_3_FILE: &str = include_str!("../../../../examples/v1_3.grid"); + const V1_3_FILE: &str = include_str!("../../../../../rust-shared/data/grid/v1_3.grid"); fn import(file_contents: &str) -> Result { serde_json::from_str::(file_contents) diff --git a/quadratic-core/src/grid/file/v1_4/file.rs b/quadratic-core/src/grid/file/v1_4/file.rs index d015a15da7..4428ada61d 100644 --- a/quadratic-core/src/grid/file/v1_4/file.rs +++ b/quadratic-core/src/grid/file/v1_4/file.rs @@ -1,9 +1,198 @@ +use std::collections::HashMap; + +use crate::grid::file::v1_4::schema as v1_4; +use crate::grid::file::v1_5::schema::{self as v1_5}; +use anyhow::Result; + +fn upgrade_spills( + sheet: &v1_4::Sheet, + spills: &HashMap>, +) -> HashMap> { + spills + .iter() + .flat_map(|(_, spill)| { + let y = spill.y; + let cell_ref = serde_json::from_str::(&spill.content.value).unwrap(); + let len = spill.content.len; + match serde_json::to_string(&cell_ref_to_sheet_pos(sheet, &cell_ref)) { + Ok(sheet_pos_string) => Some(( + y.to_string(), + v1_5::ColumnFormatType:: { + y, + content: v1_5::ColumnFormatContent { + value: sheet_pos_string, + len, + }, + }, + )), + Err(_) => None, + } + }) + .collect() +} + +fn upgrade_column(sheet: &v1_4::Sheet, x: &i64, column: &v1_4::Column) -> (i64, v1_5::Column) { + ( + *x, + v1_5::Column { + x: *x, + values: column.values.clone(), + spills: upgrade_spills(sheet, &column.spills), + align: column.align.clone(), + wrap: column.wrap.clone(), + numeric_format: column.numeric_format.clone(), + numeric_decimals: column.numeric_decimals.clone(), + numeric_commas: column.numeric_commas.clone(), + bold: column.bold.clone(), + italic: column.italic.clone(), + text_color: column.text_color.clone(), + fill_color: column.fill_color.clone(), + render_size: column.render_size.clone(), + }, + ) +} + +fn upgrade_columns(sheet: &v1_4::Sheet) -> Vec<(i64, v1_5::Column)> { + sheet + .columns + .iter() + .map(|(x, column)| upgrade_column(sheet, x, column)) + .collect() +} + +fn cell_ref_to_sheet_pos(sheet: &v1_4::Sheet, cell_ref: &v1_4::CellRef) -> v1_5::SheetPos { + let x = sheet + .columns + .iter() + .find(|column| column.1.id == cell_ref.column) + .unwrap() + .0; + let y = sheet + .rows + .iter() + .find(|row| row.1 == cell_ref.row) + .unwrap() + .0; + v1_5::SheetPos { + x, + y, + sheet_id: v1_5::Id::from(cell_ref.sheet.id.clone()), + } +} + +fn cell_ref_to_pos(sheet: &v1_4::Sheet, cell_ref: &v1_4::CellRef) -> v1_5::Pos { + let x = sheet + .columns + .iter() + .find(|column| column.1.id == cell_ref.column) + .unwrap() + .0; + let y = sheet + .rows + .iter() + .find(|row| row.1 == cell_ref.row) + .unwrap() + .0; + v1_5::Pos { x, y } +} + +fn column_id_to_x(sheet: &v1_4::Sheet, column_id: &String) -> i64 { + sheet + .columns + .iter() + .find(|column| column.1.id.id == *column_id) + .unwrap() + .0 +} + +fn upgrade_code_cells(sheet: &v1_4::Sheet) -> Vec<(v1_5::Pos, v1_5::CodeCellValue)> { + sheet + .code_cells + .clone() + .into_iter() + .map(|(cell_ref, code_cell_value)| { + let pos = cell_ref_to_pos(sheet, &cell_ref); + ( + pos, + v1_5::CodeCellValue { + language: code_cell_value.language, + code_string: code_cell_value.code_string, + formatted_code_string: code_cell_value.formatted_code_string, + last_modified: code_cell_value.last_modified, + output: code_cell_value + .output + .map(|output| v1_5::CodeCellRunOutput { + std_out: output.std_out, + std_err: output.std_err, + result: match output.result { + v1_4::CodeCellRunResult::Ok { + output_value, + cells_accessed, + } => v1_5::CodeCellRunResult::Ok { + output_value: match output_value { + v1_4::OutputValue::Single(value) => { + v1_5::OutputValue::Single(value) + } + v1_4::OutputValue::Array(array) => { + v1_5::OutputValue::Array(array) + } + }, + cells_accessed: cells_accessed + .into_iter() + .map(|cell_ref| cell_ref_to_sheet_pos(sheet, &cell_ref)) + .collect(), + }, + v1_4::CodeCellRunResult::Err { error } => { + v1_5::CodeCellRunResult::Err { error } + } + }, + spill: output.spill, + }), + }, + ) + }) + .collect() +} + +fn upgrade_borders(sheet: &v1_4::Sheet) -> v1_5::Borders { + sheet + .borders + .iter() + .map(|(column_id, borders)| { + let x = column_id_to_x(sheet, column_id); + (x.to_string(), borders.clone()) + }) + .collect() +} + +fn upgrade_sheet(sheet: &v1_4::Sheet) -> v1_5::Sheet { + let columns = upgrade_columns(sheet); + v1_5::Sheet { + id: v1_5::Id::from(sheet.id.id.clone()), + name: sheet.name.clone(), + color: sheet.color.clone(), + order: sheet.order.clone(), + offsets: sheet.offsets.clone(), + columns, + borders: upgrade_borders(sheet), + code_cells: upgrade_code_cells(sheet), + } +} + +pub(crate) fn upgrade(schema: v1_4::GridSchema) -> Result { + let schema = v1_5::GridSchema { + version: Some("1.5".into()), + sheets: schema.sheets.iter().map(upgrade_sheet).collect(), + }; + Ok(schema) +} + #[cfg(test)] mod tests { use crate::grid::file::v1_4::schema::GridSchema; use anyhow::{anyhow, Result}; - const V1_4_FILE: &str = include_str!("../../../../examples/v1_4_simple.grid"); + const V1_4_FILE: &str = include_str!("../../../../../rust-shared/data/grid/v1_4_simple.grid"); fn import(file_contents: &str) -> Result { serde_json::from_str::(file_contents) diff --git a/quadratic-core/src/grid/file/v1_5/file.rs b/quadratic-core/src/grid/file/v1_5/file.rs new file mode 100644 index 0000000000..9d672a49f8 --- /dev/null +++ b/quadratic-core/src/grid/file/v1_5/file.rs @@ -0,0 +1,24 @@ +#[cfg(test)] +mod tests { + use crate::grid::file::v1_5::schema::GridSchema; + use anyhow::{anyhow, Result}; + + const V1_5_FILE: &str = include_str!("../../../../../rust-shared/data/grid/v1_5_simple.grid"); + + fn import(file_contents: &str) -> Result { + serde_json::from_str::(file_contents) + .map_err(|e| anyhow!("Could not import file: {:?}", e)) + } + + fn export(grid_schema: &GridSchema) -> Result { + serde_json::to_string(grid_schema).map_err(|e| anyhow!("Could not export file: {:?}", e)) + } + + #[test] + fn import_and_export_a_v1_5_file() { + let imported = import(V1_5_FILE).unwrap(); + let exported = export(&imported).unwrap(); + println!("{}", exported); + // assert_eq!(V1_4_FILE, exported); + } +} diff --git a/quadratic-core/src/grid/file/v1_5/mod.rs b/quadratic-core/src/grid/file/v1_5/mod.rs new file mode 100644 index 0000000000..44973cd603 --- /dev/null +++ b/quadratic-core/src/grid/file/v1_5/mod.rs @@ -0,0 +1,2 @@ +pub mod file; +pub mod schema; diff --git a/quadratic-core/src/grid/file/v1_5/schema.rs b/quadratic-core/src/grid/file/v1_5/schema.rs new file mode 100644 index 0000000000..6350e7cf73 --- /dev/null +++ b/quadratic-core/src/grid/file/v1_5/schema.rs @@ -0,0 +1,134 @@ +use std::collections::HashMap; + +use crate::grid::{file::v1_4::schema as v1_4, SheetId}; +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GridSchema { + pub sheets: Vec, + pub version: Option, +} + +pub type Pos = v1_4::Pos; + +impl From for Pos { + fn from(pos: crate::Pos) -> Self { + Self { x: pos.x, y: pos.y } + } +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SheetPos { + pub x: i64, + pub y: i64, + pub sheet_id: Id, +} + +impl From for SheetPos { + fn from(pos: crate::SheetPos) -> Self { + Self { + x: pos.x, + y: pos.y, + sheet_id: pos.sheet_id.into(), + } + } +} + +pub type Offsets = v1_4::Offsets; + +pub type Borders = HashMap>)>>; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Sheet { + pub id: Id, + pub name: String, + pub color: Option, + pub order: String, + pub offsets: Offsets, + pub columns: Vec<(i64, Column)>, + pub borders: Borders, + #[serde(rename = "code_cells")] + pub code_cells: Vec<(Pos, CodeCellValue)>, +} + +pub type Id = v1_4::Id; + +impl From for Id { + fn from(id: SheetId) -> Self { + Self { id: id.to_string() } + } +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct CodeCellValue { + pub language: String, + pub code_string: String, + pub formatted_code_string: Option, + pub last_modified: String, + pub output: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeCellRunOutput { + pub std_out: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub std_err: Option, + pub result: CodeCellRunResult, + pub spill: bool, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +pub enum CodeCellRunResult { + Ok { + output_value: OutputValue, + cells_accessed: Vec, + }, + Err { + error: Error, + }, +} + +pub type OutputValue = v1_4::OutputValue; +pub type OutputArray = v1_4::OutputArray; +pub type OutputSize = v1_4::OutputSize; +pub type OutputValueValue = v1_4::OutputValueValue; +pub type Error = v1_4::Error; +pub type Span = v1_4::Span; +pub type RenderSize = v1_4::RenderSize; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Column { + pub x: i64, + pub values: HashMap, + pub spills: HashMap>, + pub align: HashMap>, + pub wrap: HashMap>, + #[serde(rename = "numeric_format")] + pub numeric_format: HashMap>, + #[serde(rename = "numeric_decimals")] + pub numeric_decimals: HashMap>, + #[serde(rename = "numeric_commas")] + pub numeric_commas: HashMap>, + pub bold: HashMap>, + pub italic: HashMap>, + #[serde(rename = "text_color")] + pub text_color: HashMap>, + #[serde(rename = "fill_color")] + pub fill_color: HashMap>, + #[serde(rename = "render_size")] + pub render_size: HashMap>, +} + +pub type ColumnValues = v1_4::ColumnValues; +pub type ColumnValue = v1_4::ColumnValue; +pub type ColumnFormatType = v1_4::ColumnFormatType; +pub type ColumnFormatContent = v1_4::ColumnFormatContent; +pub type NumericFormat = v1_4::NumericFormat; +pub type CellBorder = v1_4::CellBorder; diff --git a/quadratic-core/src/grid/formatting.rs b/quadratic-core/src/grid/formatting.rs index d15c89b6c8..0496f884cd 100644 --- a/quadratic-core/src/grid/formatting.rs +++ b/quadratic-core/src/grid/formatting.rs @@ -4,8 +4,25 @@ use std::ops::{BitOr, BitOrAssign}; use serde::{Deserialize, Serialize}; use strum_macros::{Display, EnumString}; +use crate::RunLengthEncoding; + use super::{block::SameValue, Column, ColumnData}; +/// Array of a single cell formatting attribute. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub enum CellFmtArray { + Align(RunLengthEncoding>), + Wrap(RunLengthEncoding>), + NumericFormat(RunLengthEncoding>), + NumericDecimals(RunLengthEncoding>), + NumericCommas(RunLengthEncoding>), + Bold(RunLengthEncoding>), + Italic(RunLengthEncoding>), + TextColor(RunLengthEncoding>), + FillColor(RunLengthEncoding>), + RenderSize(RunLengthEncoding>), +} + /// Cell formatting attribute. pub trait CellFmtAttr { type Value: Serialize + for<'d> Deserialize<'d> + fmt::Debug + Clone + Eq; diff --git a/quadratic-core/src/grid/ids.rs b/quadratic-core/src/grid/ids.rs index c229f11a61..046f846fad 100644 --- a/quadratic-core/src/grid/ids.rs +++ b/quadratic-core/src/grid/ids.rs @@ -1,17 +1,15 @@ use core::fmt; use core::fmt::Display; -use std::collections::{BTreeMap, HashMap}; use std::hash::Hash; use std::str::FromStr; use anyhow::Result; use serde::{Deserialize, Serialize}; use uuid::Uuid; + #[cfg(feature = "js")] use wasm_bindgen::prelude::*; -use crate::ArraySize; - macro_rules! uuid_wrapper_struct { ($name:ident) => { #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -44,166 +42,3 @@ macro_rules! uuid_wrapper_struct { } uuid_wrapper_struct!(SheetId); -uuid_wrapper_struct!(RowId); -uuid_wrapper_struct!(ColumnId); - -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "js", wasm_bindgen, derive(ts_rs::TS))] -pub struct CellRef { - pub sheet: SheetId, - pub column: ColumnId, - pub row: RowId, -} -impl Display for CellRef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}, {}, {}", self.sheet, self.column, self.row) - } -} - -/// Reference to a set of cells which stays the same, even as columns and rows -/// move around. It typically is constructed as a rectangle, but if columns and -/// rows move then it may no longer be rectangular. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -pub struct RegionRef { - pub sheet: SheetId, - pub columns: Vec, - pub rows: Vec, -} -impl From for RegionRef { - fn from(value: CellRef) -> Self { - RegionRef { - sheet: value.sheet, - columns: vec![value.column], - rows: vec![value.row], - } - } -} - -impl Display for RegionRef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}, {:?}, {:?}", self.sheet, self.columns, self.rows) - } -} - -impl RegionRef { - /// Iterates over cells in row-major order. - pub fn iter(&self) -> impl '_ + Iterator { - let sheet = self.sheet; - itertools::iproduct!(&self.rows, &self.columns).map(move |(&row, &column)| CellRef { - sheet, - column, - row, - }) - } - - /// Returns the size of an array containing the cells in the region, or - /// `None` if the region is empty. - pub fn size(&self) -> Option { - ArraySize::new(self.columns.len() as u32, self.rows.len() as u32) - } - - /// Returns the number of cells in the region. - pub fn len(&self) -> usize { - self.columns.len() * self.rows.len() - } - - pub fn is_empty(&self) -> bool { - self.columns.len() == 0 && self.rows.len() == 0 - } - - /// returns whether a RegionRef contains a CellRef - pub fn contains(&self, cell_ref: &CellRef) -> bool { - self.sheet == cell_ref.sheet - && self.columns.contains(&cell_ref.column) - && self.rows.contains(&cell_ref.row) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct IdMap { - id_to_index: HashMap, - index_to_id: BTreeMap, -} -impl Serialize for IdMap -where - Id: Copy + Serialize, - Idx: Copy + Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let map: HashMap = self - .id_to_index - .iter() - .map(|(id, idx)| (serde_json::to_string(id).unwrap(), *idx)) - .collect(); - map.serialize(serializer) - } -} -impl<'de, Id: Hash + Eq, Idx: Ord> Deserialize<'de> for IdMap -where - Id: Copy + for<'a> Deserialize<'a>, - Idx: Copy + for<'a> Deserialize<'a>, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let map = HashMap::<&'de str, Idx>::deserialize(deserializer)?; - let mut ret = Self::new(); - for (k, v) in map { - ret.add(serde_json::from_str(k).unwrap(), v); - } - Ok(ret) - } -} -impl Default for IdMap { - fn default() -> Self { - Self { - id_to_index: HashMap::default(), - index_to_id: BTreeMap::default(), - } - } -} -impl IdMap { - pub fn new() -> Self { - Self { - id_to_index: HashMap::new(), - index_to_id: BTreeMap::new(), - } - } - - pub fn len(&self) -> usize { - self.id_to_index.len() - } - - pub fn is_empty(&self) -> bool { - self.id_to_index.is_empty() - } - - pub fn add(&mut self, id: Id, index: Idx) { - self.id_to_index.insert(id, index); - self.index_to_id.insert(index, id); - } - pub fn index_of(&self, id: Id) -> Option { - self.id_to_index.get(&id).copied() - } - pub fn id_at(&self, idx: Idx) -> Option { - self.index_to_id.get(&idx).copied() - } - - /// Returns an iterator over indexes and corresponding IDs - pub fn iter(&self) -> impl '_ + Iterator { - self.index_to_id.iter().map(|(&index, &id)| (index, id)) - } -} -impl FromIterator<(Idx, Id)> for IdMap { - fn from_iter>(iter: T) -> Self { - let mut ret = Self::new(); - for (index, id) in iter { - ret.add(id, index); - } - ret - } -} diff --git a/quadratic-core/src/grid/mod.rs b/quadratic-core/src/grid/mod.rs index c1608e5545..dacb9c7c2d 100644 --- a/quadratic-core/src/grid/mod.rs +++ b/quadratic-core/src/grid/mod.rs @@ -13,18 +13,17 @@ mod bounds; mod code; mod column; pub mod file; -mod formatting; +pub mod formatting; mod ids; pub mod js_types; mod offsets; -mod response; pub mod series; pub mod sheet; use block::{Block, BlockContent, CellValueBlockContent, SameValue}; pub use borders::{ - generate_borders, generate_borders_full, get_cell_borders_in_rect, get_region_borders, - set_region_borders, BorderSelection, BorderStyle, CellBorderLine, CellBorders, CellSide, + generate_borders, generate_borders_full, get_cell_borders_in_rect, get_rect_borders, + set_rect_borders, BorderSelection, BorderStyle, CellBorderLine, CellBorders, CellSide, IdSpaceBorders, LegacyCellBorder, LegacyCellBorders, SheetBorders, }; pub use bounds::GridBounds; @@ -37,7 +36,10 @@ pub use formatting::{ pub use ids::*; pub use sheet::Sheet; -use crate::{Array, CellValue, Pos}; +use crate::CellValue; + +#[cfg(test)] +use crate::{Array, Pos}; #[cfg(test)] pub use borders::print_borders; @@ -61,13 +63,15 @@ impl Grid { ret.add_sheet(None).expect("error adding initial sheet"); ret } + + #[cfg(test)] pub fn from_array(base_pos: Pos, array: &Array) -> Self { let mut ret = Grid::new(); let sheet = &mut ret.sheets_mut()[0]; for ((x, y), value) in array.size().iter().zip(array.cell_values_slice()) { let x = base_pos.x + x as i64; let y = base_pos.y + y as i64; - sheet.set_cell_value(Pos { x, y }, value.clone()); + let _ = sheet.set_cell_value(Pos { x, y }, value.clone()); } ret } @@ -86,6 +90,14 @@ impl Grid { unreachable!("grid should always have at least one sheet"); } } + pub fn first_sheet(&self) -> &Sheet { + let id = self.first_sheet_id(); + self.sheet_from_id(id) + } + pub fn first_sheet_mut(&mut self) -> &mut Sheet { + let id = self.first_sheet_id(); + self.sheet_mut_from_id(id) + } pub fn sheet_ids(&self) -> Vec { self.sheets.iter().map(|sheet| sheet.id).collect() } @@ -194,6 +206,10 @@ impl Grid { let sheet_index = self.sheet_id_to_index(sheet_id).expect("bad sheet ID"); &self.sheets[sheet_index] } + pub fn try_sheet_from_id(&self, sheet_id: SheetId) -> Option<&Sheet> { + let sheet_index = self.sheet_id_to_index(sheet_id)?; + Some(&self.sheets[sheet_index]) + } pub fn sheet_mut_from_id(&mut self, sheet_id: SheetId) -> &mut Sheet { let sheet_index = self.sheet_id_to_index(sheet_id).expect("bad sheet ID"); &mut self.sheets[sheet_index] diff --git a/quadratic-core/src/grid/response.rs b/quadratic-core/src/grid/response.rs deleted file mode 100644 index 3dfaea6051..0000000000 --- a/quadratic-core/src/grid/response.rs +++ /dev/null @@ -1,24 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[must_use] -pub struct SetCellResponse { - pub old_value: V, - pub html: bool, - pub is_empty: bool, -} - -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[must_use] -pub struct GetIdResponse { - pub id: I, - pub is_new: bool, -} -impl GetIdResponse { - pub fn new(id: I) -> Self { - Self { id, is_new: true } - } - pub fn old(id: I) -> Self { - Self { id, is_new: false } - } -} diff --git a/quadratic-core/src/grid/sheet.rs b/quadratic-core/src/grid/sheet.rs index f3e8ff19ee..ffe0f71690 100644 --- a/quadratic-core/src/grid/sheet.rs +++ b/quadratic-core/src/grid/sheet.rs @@ -1,9 +1,7 @@ use std::collections::{btree_map, BTreeMap, HashMap}; -use std::ops::Range; use std::str::FromStr; use bigdecimal::BigDecimal; -use itertools::Itertools; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -12,16 +10,16 @@ use super::bounds::GridBounds; use super::code::CodeCellValue; use super::column::Column; use super::formatting::{BoolSummary, CellFmtAttr}; -use super::ids::{CellRef, ColumnId, IdMap, RowId, SheetId}; +use super::ids::SheetId; use super::js_types::{CellFormatSummary, FormattingSummary}; -use super::response::{GetIdResponse, SetCellResponse}; -use super::{NumericFormat, NumericFormatKind, RegionRef}; +use super::{NumericFormat, NumericFormatKind}; use crate::grid::{borders, SheetBorders}; use crate::{Array, ArraySize, CellValue, IsBlank, Pos, Rect}; pub mod bounds; pub mod cells; pub mod code; +pub mod formatting; pub mod rendering; pub mod sheet_offsets; @@ -32,16 +30,13 @@ pub struct Sheet { pub color: Option, pub order: String, - pub(super) column_ids: IdMap, - pub(super) row_ids: IdMap, - pub offsets: SheetOffsets, #[serde(with = "crate::util::btreemap_serde")] pub(super) columns: BTreeMap, pub(super) borders: SheetBorders, #[serde(with = "crate::util::hashmap_serde")] - pub code_cells: HashMap, + pub code_cells: HashMap, pub(super) data_bounds: GridBounds, pub(super) format_bounds: GridBounds, @@ -55,9 +50,6 @@ impl Sheet { color: None, order, - column_ids: IdMap::new(), - row_ids: IdMap::new(), - columns: BTreeMap::new(), borders: SheetBorders::new(), code_cells: HashMap::new(), @@ -76,11 +68,12 @@ impl Sheet { } /// Populates the current sheet with random values + /// todo: this does not work with multiplayer... need to fix (or delete) pub fn with_random_floats(&mut self, region: &Rect) { self.columns.clear(); let mut rng = rand::thread_rng(); for x in region.x_range() { - let (_, column) = self.get_or_create_column(x); + let column = self.get_or_create_column(x); for y in region.y_range() { let value = rng.gen_range(-10000..=10000).to_string(); column.values.set( @@ -92,16 +85,9 @@ impl Sheet { self.recalculate_bounds(); } - /// Sets a cell value and returns a response object, which contains column & - /// row IDs and the old cell value. Returns `None` if the cell was deleted - /// and did not previously exist (so no change is needed). The reason for - /// this is that the column and/or row may never have been generated, - /// because there's no need. - pub fn set_cell_value( - &mut self, - pos: Pos, - value: impl Into, - ) -> Option> { + /// Sets a cell value and returns the old cell value. Returns `None` if the cell was deleted + /// and did not previously exist (so no change is needed). + pub fn set_cell_value(&mut self, pos: Pos, value: impl Into) -> Option { let value = value.into(); let is_empty = value.is_blank(); let value: Option = if is_empty { None } else { Some(value) }; @@ -110,46 +96,27 @@ impl Sheet { if value.is_none() && !self.columns.contains_key(&pos.x) { return None; } - - let (_, column) = self.get_or_create_column(pos.x); - let old_value = column.values.set(pos.y, value.clone()).unwrap_or_default(); - - // returns if there's a change in html (html cell is added or removed from sheet) - let html = if let Some(value) = &value { - old_value.is_html() != value.is_html() - } else { - old_value.is_html() - }; - Some(SetCellResponse { - old_value, - html, - is_empty, - }) + let column = self.get_or_create_column(pos.x); + let old_value = column.values.set(pos.y, value).unwrap_or_default(); + Some(old_value) } /// Deletes all cell values in a region. This does not affect: /// /// - Formatting /// - Spilled cells (unless the source is within `region`) - pub fn delete_cell_values(&mut self, region: Rect) -> (Vec, Vec, Array) { - let row_ids = region - .y_range() - .filter_map(|y| self.get_row(y)) - .collect_vec(); - let mut column_ids = vec![]; - - let mut old_cell_values_array = Array::new_empty(region.size()); + pub fn delete_cell_values(&mut self, rect: Rect) -> Array { + let mut old_cell_values_array = Array::new_empty(rect.size()); - for x in region.x_range() { + for x in rect.x_range() { let Some(column) = self.columns.get_mut(&x) else { continue; }; - column_ids.push(column.id); - let removed = column.values.remove_range(region.y_range()); + let removed = column.values.remove_range(rect.y_range()); for block in removed { for y in block.range() { - let array_x = (x - region.min.x) as u32; - let array_y = (y - region.min.y) as u32; + let array_x = (x - rect.min.x) as u32; + let array_y = (y - rect.min.y) as u32; let Some(value) = block.get(y) else { continue }; old_cell_values_array .set(array_x, array_y, value) @@ -158,25 +125,25 @@ impl Sheet { } } - for cell_ref in self.iter_code_cells_locations_in_region(region) { - self.code_cells.remove(&cell_ref); + for sheet_pos in self.iter_code_cells_in_rect(rect) { + self.code_cells.remove(&sheet_pos); } - (column_ids, row_ids, old_cell_values_array) + old_cell_values_array + } + + pub fn iter_columns(&self) -> impl Iterator { + self.columns.iter() } /// Sets or deletes borders in a region. - pub fn set_region_borders( - &mut self, - region: &RegionRef, - borders: SheetBorders, - ) -> SheetBorders { - borders::set_region_borders(self, vec![region.clone()], borders) + pub fn set_region_borders(&mut self, rect: &Rect, borders: SheetBorders) -> SheetBorders { + borders::set_rect_borders(self, rect, borders) } /// Gets borders in a region. - pub fn get_region_borders(&self, region: RegionRef) -> SheetBorders { - borders::get_region_borders(self, vec![region]) + pub fn get_rect_borders(&self, rect: Rect) -> SheetBorders { + borders::get_rect_borders(self, &rect) } /// Returns the value of a cell (i.e., what would be returned if code asked @@ -292,7 +259,7 @@ impl Sheet { pos: Pos, value: Option, ) -> Option { - let (_, column) = self.get_or_create_column(pos.x); + let column = self.get_or_create_column(pos.x); A::column_data_mut(column).set(pos.y, value) } @@ -306,145 +273,27 @@ impl Sheet { &mut self.borders } - /// Returns an iterator over each column and its X coordinate. - pub fn iter_columns(&self) -> impl '_ + Iterator { - self.columns.iter().map(|(&x, column)| (x, column)) - } - /// Returns an iterator over each row ID and its Y coordinate. - pub fn iter_rows(&self) -> impl '_ + Iterator { - self.row_ids.iter() - } /// Returns a column of a sheet from the column index. pub(crate) fn get_column(&self, index: i64) -> Option<&Column> { self.columns.get(&index) } /// Returns a column of a sheet from its index, or creates a new column at /// that index. - pub(crate) fn get_or_create_column( - &mut self, - index: i64, - ) -> (GetIdResponse, &mut Column) { - match self.columns.entry(index) { + pub(crate) fn get_or_create_column(&mut self, x: i64) -> &mut Column { + match self.columns.entry(x) { btree_map::Entry::Vacant(e) => { - let column = e.insert(Column::new()); - self.column_ids.add(column.id, index); - (GetIdResponse::new(column.id), column) + let column = e.insert(Column::new(x)); + column } btree_map::Entry::Occupied(e) => { let column = e.into_mut(); - (GetIdResponse::old(column.id), column) + column } } } - /// Returns the ID of a row of a sheet from the row index. - pub(crate) fn get_row(&self, index: i64) -> Option { - self.row_ids.id_at(index) - } - /// Returns a row of a sheet from its index, or creates a new row at that - /// index. - pub(crate) fn get_or_create_row(&mut self, index: i64) -> GetIdResponse { - match self.row_ids.id_at(index) { - Some(id) => GetIdResponse::old(id), - None => { - let id = RowId::new(); - self.row_ids.add(id, index); - GetIdResponse::new(id) - } - } - } - - /// Returns the position references by a `CellRef`. - pub(crate) fn cell_ref_to_pos(&self, cell_ref: CellRef) -> Option { - Some(Pos { - x: self.column_ids.index_of(cell_ref.column)?, - y: self.row_ids.index_of(cell_ref.row)?, - }) - } - /// Creates a `CellRef` if the column and row already exist. - pub(crate) fn try_get_cell_ref(&self, pos: Pos) -> Option { - Some(CellRef { - sheet: self.id, - column: self.column_ids.id_at(pos.x)?, - row: self.row_ids.id_at(pos.y)?, - }) - } - /// Creates a `CellRef`, creating the column and row if they do not already - /// exist. - pub(crate) fn get_or_create_cell_ref(&mut self, pos: Pos) -> CellRef { - CellRef { - sheet: self.id, - column: self.get_or_create_column(pos.x).0.id, - row: self.get_or_create_row(pos.y).id, - } - } - - /// Returns the X coordinate of a column from its ID, or `None` if no such - /// column exists. - pub(crate) fn get_column_index(&self, column_id: ColumnId) -> Option { - self.column_ids.index_of(column_id) - } - /// Returns the Y coordinate of a row from its ID, or `None` if no such row - /// exists. - pub(crate) fn get_row_index(&self, row_id: RowId) -> Option { - self.row_ids.index_of(row_id) - } - - /// Returns contiguous ranges of X coordinates from a list of column IDs. - /// Ignores IDs for columns that don't exist. - pub(crate) fn column_ranges(&self, column_ids: &[ColumnId]) -> Vec> { - let xs = column_ids - .iter() - .filter_map(|&id| self.get_column_index(id)); - contiguous_ranges(xs) - } - /// Returns contiguous ranges of Y coordinates from a list of row IDs. - /// Ignores IDs for rows that don't exist. - pub(crate) fn row_ranges(&self, row_ids: &[RowId]) -> Vec> { - row_ranges(row_ids, &self.row_ids) - } - /// Returns a list of rectangles that exactly covers a region. Ignores - /// IDs for columns and rows that don't exist. - pub(crate) fn region_rects(&self, region: &RegionRef) -> impl Iterator { - let x_ranges = self.column_ranges(®ion.columns); - let y_ranges = self.row_ranges(®ion.rows); - itertools::iproduct!(x_ranges, y_ranges).map(|(xs, ys)| Rect::from_ranges(xs, ys)) - } - /// Returns a region of the sheet, assigning IDs to columns and rows as needed. - pub fn region(&mut self, rect: Rect) -> RegionRef { - let columns = rect - .x_range() - .map(|x| self.get_or_create_column(x).0.id) - .collect(); - let rows = rect - .y_range() - .map(|y| self.get_or_create_row(y).id) - .collect(); - RegionRef { - sheet: self.id, - columns, - rows, - } - } - /// Returns a region of the sheet, ignoring columns and rows which - /// have no contents and no IDs. - pub fn existing_region(&self, rect: Rect) -> RegionRef { - let columns = rect - .x_range() - .filter_map(|x| self.get_column(x)) - .map(|col| col.id) - .collect(); - let rows = rect.y_range().filter_map(|y| self.get_row(y)).collect(); - RegionRef { - sheet: self.id, - columns, - rows, - } - } /// Deletes all data and formatting in the sheet, effectively recreating it. pub fn clear(&mut self) { - self.column_ids = IdMap::new(); - self.row_ids = IdMap::new(); self.columns.clear(); self.code_cells.clear(); self.recalculate_bounds(); @@ -484,73 +333,45 @@ impl Sheet { /// Determines whether an output array would cause a spill error because it /// would overlap existing cell values or spills. - pub fn is_ok_to_spill_in(&self, cell_ref: CellRef, size: ArraySize) -> Option { - let Pos { x, y } = self.cell_ref_to_pos(cell_ref)?; + pub fn is_ok_to_spill_in(&self, pos: Pos, size: ArraySize) -> bool { + let Pos { x, y } = pos; let (w, h) = size.into(); // check if the output array would cause a spill - // - // TODO(ddimaria): resolve comments from @HactarCE: - // - // If we factor the per-row loop into a method on Column we can make - // this method O(n) by taking advantage of the column data structures. - // - // If this method takes a Rect, then this is just a simple loop over - // the Positions in the Rect which is nice. for i in 0..w { - for j in 0..h { - let x = x + i; - let y = y + j; + let x = x + i; + if let Some(column) = self.columns.get(&x) { + for j in 0..h { + let y = y + j; - if let Some(column) = self.columns.get(&x) { if let Some(spill) = column.spills.get(y) { - if spill != cell_ref { - return Some(true); + if spill != pos { + return true; } } if let Some(value) = column.values.get(y) { if !value.is_blank() { - return Some(true); + return true; } } } } } - - Some(false) + false } } -fn contiguous_ranges(values: impl IntoIterator) -> Vec> { - // Usually `values` is already sorted or nearly sorted, in which case this - // is `O(n)`. At worst, it's `O(n log n)`. - let mut ret: Vec> = vec![]; - for i in values.into_iter().sorted() { - match ret.last_mut() { - Some(range) if range.end == i => range.end += 1, - Some(range) if (*range).contains(&i) => continue, - _ => ret.push(i..i + 1), - } - } - ret -} - -pub fn row_ranges(row_ids: &[RowId], id_map: &IdMap) -> Vec> { - let ys = row_ids.iter().filter_map(|&id| id_map.index_of(id)); - contiguous_ranges(ys) -} - #[cfg(test)] mod test { - use std::str::FromStr; - use bigdecimal::BigDecimal; + use std::str::FromStr; use super::*; use crate::{ - controller::{auto_complete::cell_values_in_rect, GridController}, + controller::GridController, grid::{Bold, Italic, NumericFormat}, test_util::print_table, + SheetPos, }; fn test_setup(selection: &Rect, vals: &[&str]) -> (GridController, SheetId) { @@ -560,8 +381,8 @@ mod test { for y in selection.y_range() { for x in selection.x_range() { - let pos = Pos { x, y }; - grid_controller.set_cell_value(sheet_id, pos, vals[count].to_string(), None); + let sheet_pos = SheetPos { x, y, sheet_id }; + grid_controller.set_cell_value(sheet_pos, vals[count].to_string(), None); count += 1; } } @@ -570,8 +391,8 @@ mod test { } fn test_setup_basic() -> (GridController, SheetId, Rect) { - let selected: Rect = Rect::new_span(Pos { x: 2, y: 1 }, Pos { x: 5, y: 2 }); let vals = vec!["1", "2", "3", "4", "5", "6", "7", "8"]; + let selected = Rect::new_span(Pos { x: 2, y: 1 }, Pos { x: 5, y: 2 }); let (grid_controller, sheet_id) = test_setup(&selected, &vals); print_table(&grid_controller, sheet_id, selected); @@ -589,7 +410,7 @@ mod test { expected: Option, ) { let pos = Pos { x, y }; - sheet.set_cell_value(pos, CellValue::Number(BigDecimal::from_str(value).unwrap())); + let _ = sheet.set_cell_value(pos, CellValue::Number(BigDecimal::from_str(value).unwrap())); assert_eq!(sheet.decimal_places(pos, is_percentage), expected); } @@ -615,7 +436,7 @@ mod test { let mut sheet = Sheet::new(SheetId::new(), String::from(""), String::from("")); let column = sheet.get_or_create_column(3); - column.1.numeric_decimals.set(3, Some(3)); + column.numeric_decimals.set(3, Some(3)); assert_eq!(sheet.decimal_places(Pos { x: 3, y: 3 }, false), Some(3)); } @@ -624,7 +445,7 @@ mod test { fn test_current_decimal_places_text() { let mut sheet = Sheet::new(SheetId::new(), String::from(""), String::from("")); - sheet.set_cell_value( + let _ = sheet.set_cell_value( crate::Pos { x: 1, y: 2 }, CellValue::Text(String::from("abc")), ); @@ -636,7 +457,7 @@ mod test { fn test_cell_numeric_format_kind() { let mut sheet = Sheet::new(SheetId::new(), String::from(""), String::from("")); let column = sheet.get_or_create_column(0); - column.1.numeric_format.set( + column.numeric_format.set( 0, Some(NumericFormat { kind: NumericFormatKind::Percentage, @@ -664,7 +485,7 @@ mod test { print_table(&grid, sheet_id, selected); let sheet = grid.grid().sheet_from_id(sheet_id); - let values = cell_values_in_rect(&selected, sheet).unwrap(); + let values = sheet.cell_values_in_rect(&selected).unwrap(); values .into_cell_values_vec() .into_iter() @@ -676,12 +497,12 @@ mod test { fn test_delete_cell_values() { let (mut grid, sheet_id, selected) = test_setup_basic(); - grid.delete_cells_rect(sheet_id, selected, None); + grid.delete_cells_rect(selected.to_sheet_rect(sheet_id), None); let sheet = grid.grid().sheet_from_id(sheet_id); print_table(&grid, sheet_id, selected); - let values = cell_values_in_rect(&selected, sheet).unwrap(); + let values = sheet.cell_values_in_rect(&selected).unwrap(); values .into_cell_values_vec() .into_iter() @@ -706,12 +527,12 @@ mod test { // grid.set_code_cell_value((5, 2).into(), Some(code_cell)); print_table(&grid, sheet_id, view_rect); - grid.delete_cells_rect(sheet_id, selected, None); + grid.delete_cells_rect(selected.to_sheet_rect(sheet_id), None); let sheet = grid.grid().sheet_from_id(sheet_id); print_table(&grid, sheet_id, view_rect); - let values = cell_values_in_rect(&selected, sheet).unwrap(); + let values = sheet.cell_values_in_rect(&selected).unwrap(); values .into_cell_values_vec() .into_iter() @@ -754,7 +575,7 @@ mod test { fn test_get_set_formatting_value() { let (grid, sheet_id, _) = test_setup_basic(); let mut sheet = grid.grid().sheet_from_id(sheet_id).clone(); - sheet.set_formatting_value::((2, 1).into(), Some(true)); + let _ = sheet.set_formatting_value::((2, 1).into(), Some(true)); let value = sheet.get_formatting_value::((2, 1).into()); assert_eq!(value, Some(true)); @@ -773,25 +594,6 @@ mod test { }; sheet.set_code_cell_value((2, 1).into(), Some(code_cell.clone())); let value = sheet.get_code_cell((2, 1).into()); - - assert_eq!(value, Some(&code_cell)); - - let cell_ref = CellRef { - sheet: sheet_id, - column: grid - .grid() - .sheet_from_id(sheet_id) - .column_ids - .id_at(2) - .unwrap(), - row: grid - .grid() - .sheet_from_id(sheet_id) - .row_ids - .id_at(1) - .unwrap(), - }; - let value = sheet.get_code_cell_from_ref(cell_ref); assert_eq!(value, Some(&code_cell)); } @@ -819,7 +621,7 @@ mod test { fn test_formatting_summary() { let (grid, sheet_id, selected) = test_setup_basic(); let mut sheet = grid.grid().sheet_from_id(sheet_id).clone(); - sheet.set_formatting_value::((2, 1).into(), Some(true)); + let _ = sheet.set_formatting_value::((2, 1).into(), Some(true)); // just set a single bold value let value = sheet.get_formatting_summary(selected); @@ -836,7 +638,7 @@ mod test { assert_eq!(value, format_summary); // now add in a single italic value - sheet.set_formatting_value::((3, 1).into(), Some(true)); + let _ = sheet.set_formatting_value::((3, 1).into(), Some(true)); let value = sheet.get_formatting_summary(selected); format_summary.italic.is_any_true = true; assert_eq!(value, format_summary); @@ -851,7 +653,7 @@ mod test { assert_eq!(None, existing_cell_format_summary); // just set a bold value - sheet.set_formatting_value::((2, 1).into(), Some(true)); + let _ = sheet.set_formatting_value::((2, 1).into(), Some(true)); let value = sheet.get_cell_format_summary((2, 1).into()); let mut cell_format_summary = CellFormatSummary { bold: Some(true), @@ -868,7 +670,7 @@ mod test { ); // now set a italic value - sheet.set_formatting_value::((2, 1).into(), Some(true)); + let _ = sheet.set_formatting_value::((2, 1).into(), Some(true)); let value = sheet.get_cell_format_summary((2, 1).into()); cell_format_summary.italic = Some(true); assert_eq!(value, cell_format_summary); @@ -885,52 +687,27 @@ mod test { let (grid, sheet_id, _) = test_setup_basic(); let mut sheet = grid.grid().sheet_from_id(sheet_id).clone(); - // get all columns - let columns = sheet.iter_columns().collect::>(); - assert_eq!(None, columns[0].1.bold.get(1)); + let column = sheet.get_column(2); + assert_eq!(None, column.unwrap().bold.get(1)); // set a bold value, validate it's in the vec - sheet.set_formatting_value::((2, 1).into(), Some(true)); + let _ = sheet.set_formatting_value::((2, 1).into(), Some(true)); let columns = sheet.iter_columns().collect::>(); assert_eq!(Some(true), columns[0].1.bold.get(1)); // assert that get_column matches the column in the vec let index = columns[0].0; - let column = sheet.get_column(index); + let column = sheet.get_column(*index); assert_eq!(Some(true), column.unwrap().bold.get(1)); // existing column let mut sheet = sheet.clone(); let existing_column = sheet.get_or_create_column(2); - assert_eq!(column, Some(existing_column.1).as_deref()); + assert_eq!(column, Some(existing_column).as_deref()); // new column let mut sheet = sheet.clone(); let new_column = sheet.get_or_create_column(1); - assert_eq!(new_column.1, &Column::with_id(new_column.0.id)); - } - - #[test] - fn test_rows() { - let (grid, sheet_id, _) = test_setup_basic(); - let sheet = grid.grid().sheet_from_id(sheet_id).clone(); - - // get all rows - let rows = sheet.iter_rows().collect::>(); - let row = sheet.get_row(1); - assert_eq!(row, Some(rows[0].1)); - - let row = sheet.get_row(2); - assert_eq!(row, Some(rows[1].1)); - - // existing row - let mut sheet = sheet.clone(); - let existing_row = sheet.get_or_create_row(1); - assert_eq!(Some(rows[0].1), Some(existing_row.id)); - - // new row - let mut sheet = sheet.clone(); - let new_row = sheet.get_or_create_row(3); - rows.iter().for_each(|row| assert_ne!(row.1, new_row.id)); + assert_eq!(new_column, &Column::new(new_column.x)); } } diff --git a/quadratic-core/src/grid/sheet/bounds.rs b/quadratic-core/src/grid/sheet/bounds.rs index 112b0cab44..336af4f1f4 100644 --- a/quadratic-core/src/grid/sheet/bounds.rs +++ b/quadratic-core/src/grid/sheet/bounds.rs @@ -221,11 +221,11 @@ mod test { let mut sheet = Sheet::test(); assert!(sheet.is_empty()); - sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Text(String::from("test"))); + let _ = sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Text(String::from("test"))); sheet.recalculate_bounds(); assert!(!sheet.is_empty()); - sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Blank); + let _ = sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Blank); sheet.recalculate_bounds(); assert!(sheet.is_empty()); } @@ -236,8 +236,9 @@ mod test { assert_eq!(sheet.bounds(true), GridBounds::Empty); assert_eq!(sheet.bounds(false), GridBounds::Empty); - sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Text(String::from("test"))); - sheet.set_formatting_value::(Pos { x: 1, y: 1 }, Some(CellAlign::Center)); + let _ = sheet.set_cell_value(Pos { x: 0, y: 0 }, CellValue::Text(String::from("test"))); + let _ = + sheet.set_formatting_value::(Pos { x: 1, y: 1 }, Some(CellAlign::Center)); sheet.recalculate_bounds(); assert_eq!( @@ -260,12 +261,13 @@ mod test { #[test] fn test_column_bounds() { let mut sheet = Sheet::test(); - sheet.set_cell_value( + let _ = sheet.set_cell_value( Pos { x: 100, y: -50 }, CellValue::Text(String::from("test")), ); - sheet.set_cell_value(Pos { x: 100, y: 80 }, CellValue::Text(String::from("test"))); - sheet.set_formatting_value::(Pos { x: 100, y: 200 }, Some(CellAlign::Center)); + let _ = sheet.set_cell_value(Pos { x: 100, y: 80 }, CellValue::Text(String::from("test"))); + let _ = sheet + .set_formatting_value::(Pos { x: 100, y: 200 }, Some(CellAlign::Center)); sheet.recalculate_bounds(); assert_eq!(sheet.column_bounds(100, true), Some((-50, 80))); @@ -275,12 +277,13 @@ mod test { #[test] fn test_row_bounds() { let mut sheet = Sheet::test(); - sheet.set_cell_value( + let _ = sheet.set_cell_value( Pos { y: 100, x: -50 }, CellValue::Text(String::from("test")), ); - sheet.set_cell_value(Pos { y: 100, x: 80 }, CellValue::Text(String::from("test"))); - sheet.set_formatting_value::(Pos { y: 100, x: 200 }, Some(CellAlign::Center)); + let _ = sheet.set_cell_value(Pos { y: 100, x: 80 }, CellValue::Text(String::from("test"))); + let _ = sheet + .set_formatting_value::(Pos { y: 100, x: 200 }, Some(CellAlign::Center)); sheet.recalculate_bounds(); assert_eq!(sheet.row_bounds(100, true), Some((-50, 80))); @@ -291,23 +294,25 @@ mod test { fn test_columns_bounds() { let mut sheet = Sheet::test(); - sheet.set_cell_value( + let _ = sheet.set_cell_value( Pos { x: 100, y: -50 }, CellValue::Text(String::from("test")), ); - sheet.set_cell_value(Pos { x: 100, y: 80 }, CellValue::Text(String::from("test"))); - sheet.set_formatting_value::(Pos { x: 100, y: 200 }, Some(CellAlign::Center)); + let _ = sheet.set_cell_value(Pos { x: 100, y: 80 }, CellValue::Text(String::from("test"))); + let _ = sheet + .set_formatting_value::(Pos { x: 100, y: 200 }, Some(CellAlign::Center)); // set negative values - sheet.set_cell_value( + let _ = sheet.set_cell_value( Pos { x: -100, y: -50 }, CellValue::Text(String::from("test")), ); - sheet.set_cell_value( + let _ = sheet.set_cell_value( Pos { x: -100, y: -80 }, CellValue::Text(String::from("test")), ); - sheet.set_formatting_value::(Pos { x: -100, y: -200 }, Some(CellAlign::Center)); + let _ = sheet + .set_formatting_value::(Pos { x: -100, y: -200 }, Some(CellAlign::Center)); sheet.recalculate_bounds(); assert_eq!(sheet.columns_bounds(0, 100, true), Some((-50, 80))); @@ -327,23 +332,25 @@ mod test { fn test_rows_bounds() { let mut sheet = Sheet::test(); - sheet.set_cell_value( + let _ = sheet.set_cell_value( Pos { y: 100, x: -50 }, CellValue::Text(String::from("test")), ); - sheet.set_cell_value(Pos { y: 100, x: 80 }, CellValue::Text(String::from("test"))); - sheet.set_formatting_value::(Pos { y: 100, x: 200 }, Some(CellAlign::Center)); + let _ = sheet.set_cell_value(Pos { y: 100, x: 80 }, CellValue::Text(String::from("test"))); + let _ = sheet + .set_formatting_value::(Pos { y: 100, x: 200 }, Some(CellAlign::Center)); // set negative values - sheet.set_cell_value( + let _ = sheet.set_cell_value( Pos { y: -100, x: -50 }, CellValue::Text(String::from("test")), ); - sheet.set_cell_value( + let _ = sheet.set_cell_value( Pos { y: -100, x: -80 }, CellValue::Text(String::from("test")), ); - sheet.set_formatting_value::(Pos { y: -100, x: -200 }, Some(CellAlign::Center)); + let _ = sheet + .set_formatting_value::(Pos { y: -100, x: -200 }, Some(CellAlign::Center)); sheet.recalculate_bounds(); assert_eq!(sheet.rows_bounds(0, 100, true), Some((-50, 80))); @@ -363,7 +370,7 @@ mod test { fn test_find_next_column() { let mut sheet = Sheet::test(); - sheet.set_cell_value(Pos { x: 1, y: 2 }, CellValue::Text(String::from("test"))); + let _ = sheet.set_cell_value(Pos { x: 1, y: 2 }, CellValue::Text(String::from("test"))); sheet.recalculate_bounds(); assert_eq!(sheet.find_next_column(-1, 2, false, true), 1); @@ -378,7 +385,7 @@ mod test { fn test_find_next_row() { let mut sheet = Sheet::test(); - sheet.set_cell_value(Pos { y: 1, x: 2 }, CellValue::Text(String::from("test"))); + let _ = sheet.set_cell_value(Pos { y: 1, x: 2 }, CellValue::Text(String::from("test"))); sheet.recalculate_bounds(); assert_eq!(sheet.find_next_row(-1, 2, false, true), 1); diff --git a/quadratic-core/src/grid/sheet/cells.rs b/quadratic-core/src/grid/sheet/cells.rs index 4c5024e5bf..c8e3701933 100644 --- a/quadratic-core/src/grid/sheet/cells.rs +++ b/quadratic-core/src/grid/sheet/cells.rs @@ -1,6 +1,8 @@ +use anyhow::{anyhow, Result}; + use crate::{ controller::transaction_types::{CellForArray, CellsForArray}, - Pos, Rect, + Array, CellValue, Pos, Rect, }; use super::Sheet; @@ -19,4 +21,30 @@ impl Sheet { } CellsForArray::new(array, false) } + + /// In a given rect, collect all cell values into an array. + /// + /// TODO(ddimaria): is this necessary as it's more performant to just pluck the data from the sheet direclty + pub fn cell_values_in_rect(&self, &selection: &Rect) -> Result { + let values = selection + .y_range() + .flat_map(|y| { + selection + .x_range() + .map(|x| { + self.get_cell_value(Pos { x, y }) + .unwrap_or_else(|| CellValue::Blank) + }) + .collect::>() + }) + .collect(); + + Array::new_row_major(selection.size(), values).map_err(|e| { + anyhow!( + "Could not create array of size {:?}: {:?}", + selection.size(), + e + ) + }) + } } diff --git a/quadratic-core/src/grid/sheet/code.rs b/quadratic-core/src/grid/sheet/code.rs index fe8dc31788..6250d27ce2 100644 --- a/quadratic-core/src/grid/sheet/code.rs +++ b/quadratic-core/src/grid/sheet/code.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use super::Sheet; use crate::{ - grid::{CellRef, CodeCellValue, RenderSize}, + grid::{CodeCellValue, RenderSize}, CellValue, Pos, Rect, Value, }; @@ -15,8 +15,10 @@ impl Sheet { pos: Pos, code_cell: Option, ) -> Option { - let cell_ref = self.get_or_create_cell_ref(pos); - let old = self.code_cells.remove(&cell_ref); + let old = self.code_cells.remove(&pos); + + // this column has to exist since it was just created in the previous statement + let code_cell_column = self.get_or_create_column(pos.x); if let Some(code_cell) = code_cell { if let Some(output) = &code_cell.output { @@ -24,14 +26,13 @@ impl Sheet { Some(output_value) => { match output_value { Value::Single(_) => { - let (_, column) = self.get_or_create_column(pos.x); - column.spills.set(pos.y, Some(cell_ref)); + code_cell_column.spills.set(pos.y, Some(pos)); } Value::Array(array) => { // if spilled only set the top left cell if output.spill { - let (_, column) = self.get_or_create_column(pos.x); - column.spills.set(pos.y, Some(cell_ref)); + let column = self.get_or_create_column(pos.x); + column.spills.set(pos.y, Some(pos)); } // otherwise set the whole array else { @@ -42,42 +43,34 @@ impl Sheet { end: pos.y + array.height() as i64, }; for x in start..end { - let (_, column) = self.get_or_create_column(x); - column.spills.set_range(range.clone(), cell_ref); + let column = self.get_or_create_column(x); + column.spills.set_range(range.clone(), pos); } } } } } None => { - let (_, column) = self.get_or_create_column(pos.x); - column.spills.set(pos.y, Some(cell_ref)); + code_cell_column.spills.set(pos.y, Some(pos)); } } } else { - let (_, column) = self.get_or_create_column(pos.x); - column.spills.set(pos.y, Some(cell_ref)); + code_cell_column.spills.set(pos.y, Some(pos)); } - self.code_cells.insert(cell_ref, code_cell); + self.code_cells.insert(pos, code_cell); } old } /// Returns a code cell value. pub fn get_code_cell(&self, pos: Pos) -> Option<&CodeCellValue> { - self.code_cells.get(&self.try_get_cell_ref(pos)?) - } - - /// Returns a code cell value. - pub fn get_code_cell_from_ref(&self, cell_ref: CellRef) -> Option<&CodeCellValue> { - self.code_cells.get(&cell_ref) + self.code_cells.get(&pos) } pub fn get_code_cell_value(&self, pos: Pos) -> Option { let column = self.get_column(pos.x)?; - let block = column.spills.get(pos.y)?; - let code_cell_pos = self.cell_ref_to_pos(block)?; - let code_cell = self.code_cells.get(&block)?; + let code_cell_pos = column.spills.get(pos.y)?; + let code_cell = self.code_cells.get(&code_cell_pos)?; code_cell.get_output_value( (pos.x - code_cell_pos.x) as u32, (pos.y - code_cell_pos.y) as u32, @@ -86,33 +79,29 @@ impl Sheet { /// Get the spill location for a given cell_ref. Note that a spill is /// also stored as as cell_ref. - pub fn get_spill(&self, cell_ref: CellRef) -> Option { - let pos = self.cell_ref_to_pos(cell_ref)?; + pub fn get_spill(&self, pos: Pos) -> Option { let column = self.get_column(pos.x)?; column.spills.get(pos.y) } /// Returns an iterator over all locations containing code cells that may /// spill into `region`. - pub fn iter_code_cells_locations_in_region( - &self, - region: Rect, - ) -> impl Iterator { - let code_cell_refs: HashSet = self + pub fn iter_code_cells_in_rect(&self, rect: Rect) -> impl Iterator { + let code_cell_positions: HashSet = self .columns - .range(region.x_range()) + .range(rect.x_range()) .flat_map(|(_x, column)| { column .spills - .blocks_covering_range(region.y_range()) + .blocks_covering_range(rect.y_range()) .map(|block| block.content().value) }) .collect(); - code_cell_refs.into_iter() + code_cell_positions.into_iter() } - pub fn iter_code_cells_locations(&self) -> impl '_ + Iterator { + pub fn iter_code_cells_locations(&self) -> impl '_ + Iterator { self.code_cells.keys().copied() } @@ -125,26 +114,21 @@ impl Sheet { /// Checks if the deletion of a cell or a code_cell released a spill error; /// sorted by earliest last_modified. /// Returns the cell_ref and the code_cell_value if it did - pub fn spill_error_released(&self, cell_ref: CellRef) -> Option<(CellRef, CodeCellValue)> { + pub fn spill_error_released(&self, pos: Pos) -> Option<(Pos, CodeCellValue)> { self.code_cells .iter() .filter(|(_, code_cell)| code_cell.has_spill_error()) .sorted_by_key(|a| &a.1.last_modified) - .filter_map(|(code_cell_ref, code_cell)| { - let pos = self.cell_ref_to_pos(*code_cell_ref)?; + .filter_map(|(code_cell_pos, code_cell)| { let array_size = code_cell.output_size(); let rect = Rect::from_pos_and_size(pos, array_size); - - self.existing_region(rect) - .contains(&cell_ref) - .then(|| (*code_cell_ref, code_cell.to_owned())) + rect.contains(pos) + .then(|| (*code_cell_pos, code_cell.to_owned())) }) .find(|(cell_ref, code_cell)| { let array_size = code_cell.output_size(); if array_size.len() > 1 { - !self - .is_ok_to_spill_in(*cell_ref, array_size) - .unwrap_or(false) + !self.is_ok_to_spill_in(*cell_ref, array_size) } else { false } @@ -154,7 +138,7 @@ impl Sheet { #[cfg(test)] mod test { - use crate::{controller::GridController, grid::RenderSize, Rect}; + use crate::{controller::GridController, grid::RenderSize, SheetPos}; #[test] fn test_render_size() { @@ -163,8 +147,12 @@ mod test { let mut gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; gc.set_cell_render_size( - sheet_id, - Rect::single_pos(Pos { x: 0, y: 0 }), + SheetPos { + x: 0, + y: 0, + sheet_id, + } + .into(), Some(crate::grid::RenderSize { w: "10".to_string(), h: "20".to_string(), diff --git a/quadratic-core/src/grid/sheet/formatting.rs b/quadratic-core/src/grid/sheet/formatting.rs new file mode 100644 index 0000000000..3e413b21e4 --- /dev/null +++ b/quadratic-core/src/grid/sheet/formatting.rs @@ -0,0 +1,27 @@ +use crate::{grid::CellFmtAttr, Pos, RunLengthEncoding, SheetRect}; + +use super::Sheet; + +impl Sheet { + /// Set the cell formatting for a sheet_rect. + pub fn set_cell_formats_for_type( + &mut self, + sheet_rect: &SheetRect, + values: RunLengthEncoding>, + ) -> RunLengthEncoding> { + // todo: optimize this for contiguous runs of the same value + let mut old_values = RunLengthEncoding::new(); + let mut i = 0; + for y in sheet_rect.y_range() { + for x in sheet_rect.x_range() { + let pos = Pos { x, y }; + // see note above re: operations returned from set_formatting_value + let old_value = + self.set_formatting_value::(pos, values.get_at(i).unwrap().clone()); + old_values.push(old_value); + i += 1; + } + } + old_values + } +} diff --git a/quadratic-core/src/grid/sheet/rendering.rs b/quadratic-core/src/grid/sheet/rendering.rs index 7130c39c70..b95ae8b123 100644 --- a/quadratic-core/src/grid/sheet/rendering.rs +++ b/quadratic-core/src/grid/sheet/rendering.rs @@ -42,7 +42,7 @@ impl Sheet { .spills .blocks_of_range(rect.y_range()) .filter_map(move |block| { - let code_cell_pos = self.cell_ref_to_pos(block.content.value)?; + let code_cell_pos = block.content.value; let code_cell = self.code_cells.get(&block.content.value)?; let mut block_len = block.len(); @@ -172,13 +172,12 @@ impl Sheet { pub fn get_html_output(&self) -> Vec { self.code_cells .iter() - .filter_map(|(cell_ref, code_cell_value)| { + .filter_map(|(pos, code_cell_value)| { let output = code_cell_value.get_output_value(0, 0)?; if !matches!(output, CellValue::Html(_)) { return None; } - let pos = self.cell_ref_to_pos(*cell_ref)?; - let (w, h) = if let Some(render_size) = self.render_size(pos) { + let (w, h) = if let Some(render_size) = self.render_size(*pos) { (Some(render_size.w), Some(render_size.h)) } else { (None, None) @@ -229,13 +228,12 @@ impl Sheet { } /// Returns data for rendering code cells. pub fn get_render_code_cells(&self, rect: Rect) -> Vec { - self.iter_code_cells_locations_in_region(rect) - .filter_map(|cell_ref| { - let pos = self.cell_ref_to_pos(cell_ref)?; + self.iter_code_cells_in_rect(rect) + .filter_map(|pos| { if !rect.contains(pos) { return None; } - let code_cell = self.code_cells.get(&cell_ref)?; + let code_cell = self.code_cells.get(&pos)?; let output_size = code_cell.output_size(); let (state, w, h) = match &code_cell.output { Some(output) => match &output.result { @@ -269,9 +267,8 @@ impl Sheet { /// Returns data for all rendering code cells pub fn get_all_render_code_cells(&self) -> Vec { self.iter_code_cells_locations() - .filter_map(|cell_ref| { - let pos = self.cell_ref_to_pos(cell_ref)?; - let code_cell = self.code_cells.get(&cell_ref)?; + .filter_map(|pos| { + let code_cell = self.code_cells.get(&pos)?; let output_size = code_cell.output_size(); let (state, w, h) = match &code_cell.output { @@ -316,6 +313,8 @@ impl Sheet { #[cfg(test)] mod tests { + use std::collections::HashSet; + use crate::{ controller::{transaction_types::JsCodeResult, GridController}, grid::{ @@ -323,7 +322,7 @@ mod tests { Bold, CellAlign, CodeCellLanguage, CodeCellRunOutput, CodeCellRunResult, CodeCellValue, Italic, RenderSize, }, - CellValue, Error, ErrorMsg, Pos, Rect, Value, + CellValue, Error, ErrorMsg, Pos, Rect, SheetPos, Value, }; #[test] @@ -338,7 +337,7 @@ mod tests { }; assert!(!sheet.has_render_cells(rect)); - sheet.set_cell_value(Pos { x: 1, y: 2 }, CellValue::Text("test".to_string())); + let _ = sheet.set_cell_value(Pos { x: 1, y: 2 }, CellValue::Text("test".to_string())); assert!(sheet.has_render_cells(rect)); sheet.delete_cell_values(Rect::single_pos(Pos { x: 1, y: 2 })); @@ -353,7 +352,7 @@ mod tests { output: Some(CodeCellRunOutput { result: CodeCellRunResult::Ok { output_value: Value::Single(CellValue::Text("hello".to_string())), - cells_accessed: vec![], + cells_accessed: HashSet::new(), }, std_err: None, std_out: None, @@ -364,7 +363,15 @@ mod tests { ); assert!(sheet.has_render_cells(rect)); - gc.delete_cells_rect(sheet_id, Rect::single_pos(Pos { x: 2, y: 3 }), None); + gc.delete_cells_rect( + SheetPos { + x: 2, + y: 3, + sheet_id, + } + .into(), + None, + ); let sheet = gc.sheet(sheet_id); assert!(!sheet.has_render_cells(rect)); } @@ -375,21 +382,22 @@ mod tests { let sheet_id = gc.sheet_ids()[0]; let sheet = gc.grid_mut().sheet_mut_from_id(sheet_id); - sheet.set_cell_value(Pos { x: 1, y: 2 }, CellValue::Text("test".to_string())); - sheet.set_formatting_value::(Pos { x: 1, y: 2 }, Some(true)); - sheet.set_formatting_value::(Pos { x: 1, y: 2 }, Some(CellAlign::Center)); - sheet.set_cell_value(Pos { x: 1, y: 3 }, CellValue::Number(123.into())); - sheet.set_formatting_value::(Pos { x: 1, y: 3 }, Some(true)); - sheet.set_cell_value(Pos { x: 2, y: 4 }, CellValue::Html("html".to_string())); - sheet.set_cell_value(Pos { x: 2, y: 5 }, CellValue::Logical(true)); - sheet.set_cell_value( + let _ = sheet.set_cell_value(Pos { x: 1, y: 2 }, CellValue::Text("test".to_string())); + let _ = sheet.set_formatting_value::(Pos { x: 1, y: 2 }, Some(true)); + let _ = + sheet.set_formatting_value::(Pos { x: 1, y: 2 }, Some(CellAlign::Center)); + let _ = sheet.set_cell_value(Pos { x: 1, y: 3 }, CellValue::Number(123.into())); + let _ = sheet.set_formatting_value::(Pos { x: 1, y: 3 }, Some(true)); + let _ = sheet.set_cell_value(Pos { x: 2, y: 4 }, CellValue::Html("html".to_string())); + let _ = sheet.set_cell_value(Pos { x: 2, y: 5 }, CellValue::Logical(true)); + let _ = sheet.set_cell_value( Pos { x: 2, y: 6 }, CellValue::Error(Box::new(Error { span: None, msg: ErrorMsg::Spill, })), ); - sheet.set_cell_value( + let _ = sheet.set_cell_value( Pos { x: 3, y: 3 }, CellValue::Error(Box::new(Error { span: None, @@ -500,13 +508,16 @@ mod tests { let mut gc = GridController::new(); let sheet_id = gc.sheet_ids()[0]; gc.set_cell_code( - sheet_id, - Pos { x: 1, y: 2 }, + SheetPos { + x: 1, + y: 2, + sheet_id, + }, CodeCellLanguage::Python, "".to_string(), None, ); - gc.calculation_complete(JsCodeResult::new( + gc.after_calculation_async(JsCodeResult::new( true, None, None, @@ -531,8 +542,12 @@ mod tests { } ); gc.set_cell_render_size( - sheet_id, - Rect::single_pos(Pos { x: 1, y: 2 }), + SheetPos { + x: 1, + y: 2, + sheet_id, + } + .into(), Some(RenderSize { w: "1".into(), h: "2".into(), diff --git a/quadratic-core/src/grid/sheet/sheet_offsets/sheet_offsets_wasm.rs b/quadratic-core/src/grid/sheet/sheet_offsets/sheet_offsets_wasm.rs index c958eadd31..7f19c45772 100644 --- a/quadratic-core/src/grid/sheet/sheet_offsets/sheet_offsets_wasm.rs +++ b/quadratic-core/src/grid/sheet/sheet_offsets/sheet_offsets_wasm.rs @@ -1,4 +1,4 @@ -use super::{resize_transient::TransientResize, SheetOffsets}; +use crate::grid::sheet::sheet_offsets::{resize_transient::TransientResize, SheetOffsets}; use crate::ScreenRect; use js_sys::Int32Array; use wasm_bindgen::prelude::wasm_bindgen; diff --git a/quadratic-core/src/grid/tests/mod.rs b/quadratic-core/src/grid/tests/mod.rs index 6d5173354f..dcf8c685a2 100644 --- a/quadratic-core/src/grid/tests/mod.rs +++ b/quadratic-core/src/grid/tests/mod.rs @@ -41,7 +41,7 @@ fn proptest_sheet_writes_internal(writes: Vec<(Pos, CellValue)>) { let mut hashmap_of_truth = HashMap::new(); for (pos, cell_value) in &writes { - sheet.set_cell_value(*pos, cell_value.clone()); + let _ = sheet.set_cell_value(*pos, cell_value.clone()); hashmap_of_truth.insert(*pos, cell_value); } diff --git a/quadratic-core/src/grid/tests/order.rs b/quadratic-core/src/grid/tests/order.rs index 05cfa6f189..6637a4cfab 100644 --- a/quadratic-core/src/grid/tests/order.rs +++ b/quadratic-core/src/grid/tests/order.rs @@ -56,3 +56,15 @@ fn test_order_move_sheet() { assert_eq!(grid.sheets[1].name, String::from('1')); assert_eq!(grid.sheets[2].name, String::from('2')); } + +#[test] +fn test_first_sheet() { + let grid = setup_grid(); + assert_eq!(grid.first_sheet().name, String::from('0')); +} + +#[test] +fn test_first_sheet_id() { + let grid = setup_grid(); + assert_eq!(grid.first_sheet_id(), grid.sheets[0].id); +} diff --git a/quadratic-core/src/lib.rs b/quadratic-core/src/lib.rs index 05acc1674e..9aa100d8d8 100644 --- a/quadratic-core/src/lib.rs +++ b/quadratic-core/src/lib.rs @@ -6,7 +6,6 @@ pub mod util; #[macro_use] mod error; mod color; -mod computation; pub mod controller; pub mod ext; pub mod formulas; @@ -14,8 +13,7 @@ pub mod grid; mod position; mod rle; mod span; -#[cfg(test)] -mod test_util; +pub mod test_util; mod values; #[cfg(feature = "js")] pub mod wasm_bindings; diff --git a/quadratic-core/src/position.rs b/quadratic-core/src/position.rs index fd13a30a28..cfa3afb3ae 100644 --- a/quadratic-core/src/position.rs +++ b/quadratic-core/src/position.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "js")] use wasm_bindgen::prelude::*; -use crate::{grid::SheetId, ArraySize}; +use crate::{grid::SheetId, ArraySize, QUADRANT_SIZE}; /// Cell position {x, y}. #[cfg_attr(test, derive(proptest_derive::Arbitrary))] @@ -29,11 +29,19 @@ pub struct Pos { impl Pos { pub const ORIGIN: Self = Self { x: 0, y: 0 }; + pub fn to_sheet_pos(&self, sheet_id: SheetId) -> SheetPos { + SheetPos { + x: self.x, + y: self.y, + sheet_id, + } + } + /// Returns which quadrant the cell position is in. pub fn quadrant(self) -> (i64, i64) { ( - self.x.div_euclid(crate::QUADRANT_SIZE as _), - self.y.div_euclid(crate::QUADRANT_SIZE as _), + self.x.div_euclid(QUADRANT_SIZE as _), + self.y.div_euclid(QUADRANT_SIZE as _), ) } @@ -46,12 +54,6 @@ impl Pos { format!("{col}{}", self.y) } } - - /// Adds information about which sheet the position is in. - pub fn with_sheet(self, sheet_id: SheetId) -> SheetPos { - let Pos { x, y } = self; - SheetPos { x, y, sheet_id } - } } impl From<(i64, i64)> for Pos { fn from(pos: (i64, i64)) -> Self { @@ -59,8 +61,11 @@ impl From<(i64, i64)> for Pos { } } impl From for Pos { - fn from(pos: SheetPos) -> Self { - Pos { x: pos.x, y: pos.y } + fn from(sheet_pos: SheetPos) -> Self { + Pos { + x: sheet_pos.x, + y: sheet_pos.y, + } } } impl fmt::Display for Pos { @@ -97,6 +102,14 @@ impl Rect { } } + pub fn to_sheet_rect(&self, sheet_id: SheetId) -> SheetRect { + SheetRect { + min: self.min, + max: self.max, + sheet_id, + } + } + pub fn from_numbers(x: i64, y: i64, w: i64, h: i64) -> Rect { Rect { min: Pos { x, y }, @@ -183,7 +196,7 @@ impl Rect { } pub fn is_empty(&self) -> bool { - self.width() == 0 && self.height() == 0 + self.width() == 0 || self.height() == 0 } pub fn translate(&mut self, x: i64, y: i64) { @@ -192,6 +205,11 @@ impl Rect { self.max.x += x; self.max.y += y; } + + pub fn iter(self) -> impl Iterator { + let Rect { min, max } = self; + (min.y..=max.y).flat_map(move |y| (min.x..=max.x).map(move |x| Pos { x, y })) + } } #[derive(Serialize, Deserialize, Debug, Default, Copy, Clone)] @@ -211,12 +229,19 @@ pub struct SheetPos { pub y: i64, pub sheet_id: SheetId, } + impl fmt::Display for SheetPos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} ({}, {})", self.sheet_id, self.x, self.y) } } +impl From<(i64, i64, SheetId)> for SheetPos { + fn from((x, y, sheet_id): (i64, i64, SheetId)) -> Self { + Self { x, y, sheet_id } + } +} + /// Used for referencing a range during computation. #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct SheetRect { @@ -229,19 +254,46 @@ pub struct SheetRect { } impl SheetRect { - /// Constructs a new rectangle containing only a single cell. - pub fn single_pos(pos: SheetPos) -> SheetRect { + pub fn single_sheet_pos(sheet_pos: SheetPos) -> SheetRect { + SheetRect { + min: sheet_pos.into(), + max: sheet_pos.into(), + sheet_id: sheet_pos.sheet_id, + } + } + + pub fn single_pos(pos: Pos, sheet_id: SheetId) -> SheetRect { + SheetRect { + min: pos, + max: pos, + sheet_id, + } + } + + /// Constructs a new SheetRect from two positions and a sheet id. + pub fn new_pos_span(pos1: Pos, pos2: Pos, sheet_id: SheetId) -> SheetRect { + use std::cmp::{max, min}; SheetRect { - sheet_id: pos.sheet_id, - min: Pos { x: pos.x, y: pos.y }, - max: Pos { x: pos.x, y: pos.y }, + min: Pos { + x: min(pos1.x, pos2.x), + y: min(pos1.y, pos2.y), + }, + max: Pos { + x: max(pos1.x, pos2.x), + y: max(pos1.y, pos2.y), + }, + sheet_id, } } + + pub fn new_span(pos1: SheetPos, pos2: SheetPos) -> SheetRect { + SheetRect::new_pos_span(pos1.into(), pos2.into(), pos1.sheet_id) + } /// Returns whether a position is contained within the rectangle. - pub fn contains(self, pos: SheetPos) -> bool { - self.sheet_id == pos.sheet_id - && self.x_range().contains(&pos.x) - && self.y_range().contains(&pos.y) + pub fn contains(self, sheet_pos: SheetPos) -> bool { + self.sheet_id == sheet_pos.sheet_id + && self.x_range().contains(&sheet_pos.x) + && self.y_range().contains(&sheet_pos.y) } /// Returns whether a rectangle intersects with the rectangle. pub fn intersects(self, other: SheetRect) -> bool { @@ -260,6 +312,32 @@ impl SheetRect { pub fn y_range(self) -> Range { self.min.y..self.max.y + 1 } + pub fn width(&self) -> usize { + (self.max.x - self.min.x + 1) as usize + } + pub fn height(&self) -> usize { + (self.max.y - self.min.y + 1) as usize + } + pub fn len(&self) -> usize { + self.width() * self.height() + } + pub fn is_empty(&self) -> bool { + self.width() == 0 && self.height() == 0 + } + pub fn size(&self) -> ArraySize { + ArraySize::new(self.width() as u32, self.height() as u32) + .expect("empty rectangle has no size") + } + pub fn iter(self) -> impl Iterator { + let SheetRect { min, max, .. } = self; + (min.y..=max.y).flat_map(move |y| { + (min.x..=max.x).map(move |x| SheetPos { + x, + y, + sheet_id: self.sheet_id, + }) + }) + } } impl fmt::Display for SheetRect { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -271,27 +349,270 @@ impl fmt::Display for SheetRect { } } +impl From for SheetRect { + fn from(sheet_pos: SheetPos) -> Self { + SheetRect { + min: sheet_pos.into(), + max: sheet_pos.into(), + sheet_id: sheet_pos.sheet_id, + } + } +} + +// cannot go from Rect to SheetRect; need to use Rect.to_sheet_rect(sheet_id) +#[allow(clippy::from_over_into)] +impl Into for SheetRect { + fn into(self) -> Rect { + Rect { + min: self.min, + max: self.max, + } + } +} + impl SheetPos { pub fn new(sheet_id: SheetId, x: i64, y: i64) -> Self { Self { sheet_id, x, y } } - pub fn without_sheet(self) -> Pos { - let SheetPos { x, y, .. } = self; - Pos { x, y } - } } -impl From for Vec { - fn from(rect: SheetRect) -> Vec { - let mut sheet_pos = vec![]; - for x in rect.min.x..=rect.max.x { - for y in rect.min.y..=rect.max.y { - sheet_pos.push(SheetPos { - sheet_id: rect.sheet_id, - x, - y, - }); + +#[cfg(test)] +mod test { + use crate::{grid::SheetId, Pos, Rect, SheetPos, SheetRect, QUADRANT_SIZE}; + + #[test] + fn test_to_sheet_pos() { + let pos = Pos { x: 1, y: 2 }; + let sheet_id = SheetId::new(); + assert_eq!( + pos.to_sheet_pos(sheet_id), + SheetPos { + x: 1, + y: 2, + sheet_id } - } - sheet_pos + ); + } + + #[test] + fn test_quadrant_size() { + let pos = Pos { x: 1, y: 2 }; + assert_eq!(pos.quadrant(), (0, 0)); + let quadrant_size = QUADRANT_SIZE as i64; + let pos = Pos { + x: quadrant_size + 1, + y: quadrant_size + 1, + }; + assert_eq!(pos.quadrant(), (1, 1)); + } + + #[test] + fn test_a1_string() { + let pos = Pos { x: 1, y: 2 }; + assert_eq!(pos.a1_string(), "B2"); + let pos = Pos { x: 0, y: 0 }; + assert_eq!(pos.a1_string(), "A0"); + let pos = Pos { x: 26, y: 0 }; + assert_eq!(pos.a1_string(), "AA0"); + let pos = Pos { x: 26, y: 1 }; + assert_eq!(pos.a1_string(), "AA1"); + let pos = Pos { x: 26, y: -1 }; + assert_eq!(pos.a1_string(), "AAn1"); + } + + #[test] + fn test_pos_into() { + let pos: Pos = (1, 2).into(); + assert_eq!(pos, Pos { x: 1, y: 2 }); + + let sheet_id = SheetId::new(); + let sheet_pos = SheetPos { + x: 1, + y: 2, + sheet_id, + }; + let check_pos: Pos = sheet_pos.into(); + assert_eq!(check_pos, Pos { x: 1, y: 2 }); + + let pos: Pos = (1, 2).into(); + assert_eq!(pos, Pos { x: 1, y: 2 }); + + let sheet_pos = SheetPos { + x: 1, + y: 2, + sheet_id, + }; + let pos: Pos = sheet_pos.into(); + assert_eq!(pos, Pos { x: 1, y: 2 }); + } + + #[test] + fn test_rect_new_span() { + let pos1 = Pos { x: 1, y: 2 }; + let pos2 = Pos { x: 3, y: 4 }; + let rect = Rect::new_span(pos1, pos2); + assert_eq!(rect.min, Pos { x: 1, y: 2 }); + assert_eq!(rect.max, Pos { x: 3, y: 4 }); + } + + #[test] + fn test_to_sheet_rect() { + let pos1 = Pos { x: 1, y: 2 }; + let pos2 = Pos { x: 3, y: 4 }; + let sheet_id = SheetId::new(); + let rect = Rect::new_span(pos1, pos2).to_sheet_rect(sheet_id); + assert_eq!(rect.min, Pos { x: 1, y: 2 }); + assert_eq!(rect.max, Pos { x: 3, y: 4 }); + assert_eq!(rect.sheet_id, sheet_id); + } + + #[test] + fn test_from_numbers() { + let rect = Rect::from_numbers(1, 2, 3, 4); + assert_eq!(rect.min, Pos { x: 1, y: 2 }); + assert_eq!(rect.max, Pos { x: 3, y: 5 }); + } + + #[test] + fn test_single_pos() { + let rect = Rect::single_pos(Pos { x: 1, y: 2 }); + assert_eq!(rect.min, Pos { x: 1, y: 2 }); + assert_eq!(rect.max, Pos { x: 1, y: 2 }); + } + + #[test] + fn test_extend_to() { + let mut rect = Rect::single_pos(Pos { x: 1, y: 2 }); + rect.extend_to(Pos { x: 3, y: 4 }); + assert_eq!(rect.min, Pos { x: 1, y: 2 }); + assert_eq!(rect.max, Pos { x: 3, y: 4 }); + } + + #[test] + fn test_from_ranges() { + let rect = Rect::from_ranges(1..4, 2..5); + assert_eq!(rect.min, Pos { x: 1, y: 2 }); + assert_eq!(rect.max, Pos { x: 3, y: 4 }); + } + + #[test] + fn test_size() { + let rect = Rect::from_ranges(1..4, 2..5); + assert_eq!(rect.size(), crate::ArraySize::new(3, 3).unwrap()); + } + + #[test] + fn test_from_pos_and_size() { + let rect = + Rect::from_pos_and_size(Pos { x: 1, y: 2 }, crate::ArraySize::new(3, 4).unwrap()); + assert_eq!(rect.min, Pos { x: 1, y: 2 }); + assert_eq!(rect.max, Pos { x: 3, y: 5 }); + } + + #[test] + fn test_contains() { + let rect = Rect::from_ranges(1..4, 2..5); + assert!(rect.contains(Pos { x: 1, y: 2 })); + assert!(rect.contains(Pos { x: 3, y: 4 })); + assert!(!rect.contains(Pos { x: 0, y: 2 })); + assert!(!rect.contains(Pos { x: 1, y: 1 })); + assert!(!rect.contains(Pos { x: 4, y: 2 })); + assert!(!rect.contains(Pos { x: 1, y: 5 })); + } + + #[test] + fn test_intersects() { + let rect = Rect::from_ranges(1..5, 2..6); + assert!(rect.intersects(Rect::from_ranges(1..4, 2..5))); + assert!(rect.intersects(Rect::from_ranges(2..5, 3..6))); + assert!(rect.intersects(Rect::from_ranges(0..2, 2..5))); + assert!(rect.intersects(Rect::from_ranges(1..4, 0..3))); + assert!(rect.intersects(Rect::from_ranges(4..6, 2..5))); + assert!(rect.intersects(Rect::from_ranges(1..4, 5..7))); + assert!(!rect.intersects(Rect::from_ranges(0..1, 2..5))); + assert!(!rect.intersects(Rect::from_ranges(1..4, 0..1))); + assert!(!rect.intersects(Rect::from_ranges(5..6, 2..5))); + assert!(!rect.intersects(Rect::from_ranges(1..4, 6..7))); + } + + #[test] + fn test_x_range() { + let rect = Rect::from_ranges(1..4, 2..5); + assert_eq!(rect.x_range(), 1..4); + } + + #[test] + fn test_y_range() { + let rect = Rect::from_ranges(1..4, 2..5); + assert_eq!(rect.y_range(), 2..5); + } + + #[test] + fn test_width() { + let rect = Rect::from_ranges(1..4, 2..5); + assert_eq!(rect.width(), 3); + } + + #[test] + fn test_height() { + let rect = Rect::from_ranges(1..4, 2..5); + assert_eq!(rect.height(), 3); + } + + #[test] + fn test_len() { + let rect = Rect::from_ranges(1..4, 2..5); + assert_eq!(rect.len(), 9); + } + + #[test] + fn test_is_empty() { + let rect = Rect::from_ranges(1..4, 2..5); + assert!(!rect.is_empty()); + let rect = Rect::from_numbers(0, 1, 1, 0); + assert!(rect.is_empty()); + let rect = Rect::from_numbers(0, 1, 0, 1); + assert!(rect.is_empty()); + } + + #[test] + fn test_translate() { + let mut rect = Rect::from_ranges(1..4, 2..5); + rect.translate(1, 2); + assert_eq!(rect.min, Pos { x: 2, y: 4 }); + assert_eq!(rect.max, Pos { x: 4, y: 6 }); + } + + #[test] + fn test_iter() { + let rect = Rect::from_ranges(1..4, 2..5); + let mut iter = rect.iter(); + assert_eq!(iter.next(), Some(Pos { x: 1, y: 2 })); + assert_eq!(iter.next(), Some(Pos { x: 2, y: 2 })); + assert_eq!(iter.next(), Some(Pos { x: 3, y: 2 })); + assert_eq!(iter.next(), Some(Pos { x: 1, y: 3 })); + assert_eq!(iter.next(), Some(Pos { x: 2, y: 3 })); + assert_eq!(iter.next(), Some(Pos { x: 3, y: 3 })); + assert_eq!(iter.next(), Some(Pos { x: 1, y: 4 })); + assert_eq!(iter.next(), Some(Pos { x: 2, y: 4 })); + assert_eq!(iter.next(), Some(Pos { x: 3, y: 4 })); + assert_eq!(iter.next(), None); + } + + #[test] + fn test_sheet_rect_new_pos_span() { + let pos1 = SheetPos { + x: 1, + y: 2, + sheet_id: SheetId::new(), + }; + let pos2 = SheetPos { + x: 3, + y: 4, + sheet_id: SheetId::new(), + }; + let rect = SheetRect::new_span(pos1, pos2); + assert_eq!(rect.min, Pos { x: 1, y: 2 }); + assert_eq!(rect.max, Pos { x: 3, y: 4 }); } } diff --git a/quadratic-core/src/values/array.rs b/quadratic-core/src/values/array.rs index 73ccc3596b..4e0a0832d9 100644 --- a/quadratic-core/src/values/array.rs +++ b/quadratic-core/src/values/array.rs @@ -7,11 +7,7 @@ use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; use super::{ArraySize, Axis, CellValue, Spanned, Value}; -use crate::{ - controller::operation::Operation, - grid::{CellRef, Sheet}, - CodeResult, ErrorMsg, Pos, -}; +use crate::{controller::operations::operation::Operation, grid::Sheet, CodeResult, ErrorMsg, Pos}; #[macro_export] macro_rules! array { @@ -263,44 +259,30 @@ impl Array { Ok(NonZeroU32::new(common_len).expect("bad array size")) } - // todo: this is super complicated; we need to move the number formats into CellValue to simplify this pub fn from_string_list( - start: CellRef, + start: Pos, sheet: &mut Sheet, v: Vec>, ) -> (Option, Vec) { let size = ArraySize::new(v[0].len() as u32, v.len() as u32).unwrap(); let values; - let pos = sheet.cell_ref_to_pos(start); - if let Some(pos) = pos { - let mut ops = vec![]; - let Pos { mut x, mut y } = pos; - values = v - .iter() - .flatten() - .map(|s| { - let column_id = sheet.get_or_create_column(x).0.id; - let row_id = sheet.get_or_create_row(y).id; - let cell_ref = CellRef { - sheet: start.sheet, - column: column_id, - row: row_id, - }; - x += 1; - if x == v[0].len() as i64 + pos.x { - x = pos.x; - y += 1; - } - let (value, updated_ops) = CellValue::from_string(s, cell_ref, sheet); - ops.extend(updated_ops); - value - }) - .collect(); - return (Some(Array { size, values }), ops); - } - - // return nothing when pos is not defined - (None, vec![]) + let mut ops = vec![]; + let Pos { mut x, mut y } = start; + values = v + .iter() + .flatten() + .map(|s| { + x += 1; + if x == v[0].len() as i64 + start.x { + x = start.x; + y += 1; + } + let (value, updated_ops) = CellValue::from_string(s, start, sheet); + ops.extend(updated_ops); + value + }) + .collect(); + (Some(Array { size, values }), ops) } } diff --git a/quadratic-core/src/values/cellvalue.rs b/quadratic-core/src/values/cellvalue.rs index e6328b1cf9..fd3795e740 100644 --- a/quadratic-core/src/values/cellvalue.rs +++ b/quadratic-core/src/values/cellvalue.rs @@ -5,9 +5,9 @@ use serde::{Deserialize, Serialize}; use super::{Duration, Instant, IsBlank}; use crate::{ - controller::{formatting::CellFmtArray, operation::Operation}, - grid::{CellRef, NumericDecimals, NumericFormat, NumericFormatKind, Sheet}, - CodeResult, Error, RunLengthEncoding, + controller::operations::operation::Operation, + grid::{formatting::CellFmtArray, NumericDecimals, NumericFormat, NumericFormatKind, Sheet}, + CodeResult, Error, Pos, RunLengthEncoding, SheetRect, }; // todo: fill this out @@ -382,14 +382,13 @@ impl CellValue { } } + // todo: this needs to be reworked under the new paradigm /// Converts a string to a CellValue, updates number formatting, and returns reverse Ops - pub fn from_string( - s: &String, - cell_ref: CellRef, - sheet: &mut Sheet, - ) -> (CellValue, Vec) { + pub fn from_string(s: &String, pos: Pos, sheet: &mut Sheet) -> (CellValue, Vec) { let mut ops = vec![]; let value: CellValue; + let sheet_rect = SheetRect::single_pos(pos, sheet.id); + // check for currency if let Some((currency, number)) = CellValue::unpack_currency(s) { value = CellValue::Number(number); @@ -397,25 +396,23 @@ impl CellValue { kind: NumericFormatKind::Currency, symbol: Some(currency), }; - if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { - sheet.set_formatting_value::(pos, Some(numeric_format.clone())); + sheet.set_formatting_value::(pos, Some(numeric_format.clone())); + ops.push(Operation::SetCellFormats { + sheet_rect, + attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( + Some(numeric_format), + 1, + )), + }); + + // only change decimals if it hasn't already been set + if sheet.get_formatting_value::(pos).is_none() { + sheet.set_formatting_value::(pos, Some(2)); ops.push(Operation::SetCellFormats { - region: cell_ref.into(), - attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( - Some(numeric_format), - 1, - )), + sheet_rect, + attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat(Some(2), 1)), }); - - // only change decimals if it hasn't already been set - if sheet.get_formatting_value::(pos).is_none() { - sheet.set_formatting_value::(pos, Some(2)); - ops.push(Operation::SetCellFormats { - region: cell_ref.into(), - attr: CellFmtArray::NumericDecimals(RunLengthEncoding::repeat(Some(2), 1)), - }); - } } } else if let Ok(bd) = BigDecimal::from_str(s) { value = CellValue::Number(bd); @@ -425,11 +422,9 @@ impl CellValue { kind: NumericFormatKind::Percentage, symbol: None, }; - if let Some(pos) = sheet.cell_ref_to_pos(cell_ref) { - sheet.set_formatting_value::(pos, Some(numeric_format.clone())); - } + sheet.set_formatting_value::(pos, Some(numeric_format.clone())); ops.push(Operation::SetCellFormats { - region: cell_ref.into(), + sheet_rect, attr: CellFmtArray::NumericFormat(RunLengthEncoding::repeat( Some(numeric_format), 1, diff --git a/quadratic-core/src/wasm_bindings/controller/borders.rs b/quadratic-core/src/wasm_bindings/controller/borders.rs index 373f4f60fc..d6dd7c8c5d 100644 --- a/quadratic-core/src/wasm_bindings/controller/borders.rs +++ b/quadratic-core/src/wasm_bindings/controller/borders.rs @@ -10,13 +10,15 @@ impl GridController { &mut self, sheet_id: String, rect: Rect, - selection: BorderSelection, // TODO: Vec + selection: BorderSelection, // TODO: Vec style: Option, cursor: Option, ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); Ok(serde_wasm_bindgen::to_value( - &self.set_borders(sheet_id, rect, vec![selection], style, cursor).await, + &self + .set_borders(rect.to_sheet_rect(sheet_id), vec![selection], style, cursor) + .await, )?) } } diff --git a/quadratic-core/src/wasm_bindings/controller/cells.rs b/quadratic-core/src/wasm_bindings/controller/cells.rs index 11f3ef2916..3cca35120b 100644 --- a/quadratic-core/src/wasm_bindings/controller/cells.rs +++ b/quadratic-core/src/wasm_bindings/controller/cells.rs @@ -72,10 +72,15 @@ impl GridController { value: String, cursor: Option, ) -> Result { - let sheet_id = SheetId::from_str(&sheet_id).unwrap(); - Ok(serde_wasm_bindgen::to_value( - &self.set_cell_value(sheet_id, *pos, value, cursor), - )?) + if let Ok(sheet_id) = SheetId::from_str(&sheet_id) { + Ok(serde_wasm_bindgen::to_value(&self.set_cell_value( + pos.to_sheet_pos(sheet_id), + value, + cursor, + ))?) + } else { + Err(JsValue::from_str("Invalid sheet id")) + } } /// changes the decimal places @@ -88,10 +93,16 @@ impl GridController { delta: isize, cursor: Option, ) -> Result { - let sheet_id = SheetId::from_str(&sheet_id).unwrap(); - Ok(serde_wasm_bindgen::to_value(&self.change_decimal_places( - sheet_id, source, rect, delta, cursor, - ))?) + if let Ok(sheet_id) = SheetId::from_str(&sheet_id) { + Ok(serde_wasm_bindgen::to_value(&self.change_decimal_places( + source.to_sheet_pos(sheet_id), + rect.to_sheet_rect(sheet_id), + delta, + cursor, + ))?) + } else { + Err(JsValue::from_str("Invalid sheet id")) + } } /// gets an editable string for a cell @@ -115,12 +126,12 @@ impl GridController { pub fn js_delete_cell_values( &mut self, sheet_id: String, - region: &Rect, + rect: &Rect, cursor: Option, ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); Ok(serde_wasm_bindgen::to_value( - &self.delete_cells_rect(sheet_id, *region, cursor), + &self.delete_cells_rect(rect.to_sheet_rect(sheet_id), cursor), )?) } @@ -171,8 +182,7 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); Ok(serde_wasm_bindgen::to_value(&self.set_cell_code( - sheet_id, - pos, + pos.to_sheet_pos(sheet_id), language, code_string, cursor, diff --git a/quadratic-core/src/wasm_bindings/controller/clipboard.rs b/quadratic-core/src/wasm_bindings/controller/clipboard.rs index f16fc63537..8e2961cb3b 100644 --- a/quadratic-core/src/wasm_bindings/controller/clipboard.rs +++ b/quadratic-core/src/wasm_bindings/controller/clipboard.rs @@ -13,7 +13,7 @@ impl GridController { #[wasm_bindgen(js_name = "copyToClipboard")] pub fn js_copy_to_clipboard(&self, sheet_id: String, rect: &Rect) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); - let (plain_text, html) = self.copy_to_clipboard(sheet_id, *rect); + let (plain_text, html) = self.copy_to_clipboard(rect.to_sheet_rect(sheet_id)); let output = JsClipboard { plain_text, html, @@ -31,7 +31,8 @@ impl GridController { cursor: Option, ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); - let (summary, plain_text, html) = self.cut_to_clipboard(sheet_id, *rect, cursor); + let (summary, plain_text, html) = + self.cut_to_clipboard(rect.to_sheet_rect(sheet_id), cursor); let output = JsClipboard { plain_text, html, @@ -51,7 +52,8 @@ impl GridController { cursor: Option, ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); - let output = self.paste_from_clipboard(sheet_id, pos, plain_text, html, cursor); + let output = + self.paste_from_clipboard(pos.to_sheet_pos(sheet_id), plain_text, html, cursor); Ok(serde_wasm_bindgen::to_value(&output).map_err(|e| e.to_string())?) } } diff --git a/quadratic-core/src/wasm_bindings/controller/formatting.rs b/quadratic-core/src/wasm_bindings/controller/formatting.rs index 019dd6443d..c75e85aa8d 100644 --- a/quadratic-core/src/wasm_bindings/controller/formatting.rs +++ b/quadratic-core/src/wasm_bindings/controller/formatting.rs @@ -37,9 +37,11 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); let value: Option = serde_wasm_bindgen::from_value(align).unwrap(); - Ok(serde_wasm_bindgen::to_value( - &self.set_cell_align(sheet_id, *rect, value, cursor), - )?) + Ok(serde_wasm_bindgen::to_value(&self.set_cell_align( + rect.to_sheet_rect(sheet_id), + value, + cursor, + ))?) } /// Sets cell wrap formatting given as an optional [`CellWrap`]. @@ -55,9 +57,11 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); let value: Option = serde_wasm_bindgen::from_value(wrap).unwrap(); - Ok(serde_wasm_bindgen::to_value( - &self.set_cell_wrap(sheet_id, *rect, value, cursor), - )?) + Ok(serde_wasm_bindgen::to_value(&self.set_cell_wrap( + rect.to_sheet_rect(sheet_id), + value, + cursor, + ))?) } /// Sets cells numeric_format to normal @@ -72,7 +76,7 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); Ok(serde_wasm_bindgen::to_value( - &self.remove_number_formatting(sheet_id, rect, cursor), + &self.remove_number_formatting(&rect.to_sheet_rect(sheet_id), cursor), )?) } @@ -87,10 +91,9 @@ impl GridController { symbol: String, cursor: Option, ) -> Result { - let sheet = SheetId::from_str(&sheet_id).unwrap(); + let sheet_id = SheetId::from_str(&sheet_id).unwrap(); Ok(serde_wasm_bindgen::to_value(&self.set_currency( - sheet, - rect, + &rect.to_sheet_rect(sheet_id), Some(symbol), cursor, ))?) @@ -112,7 +115,7 @@ impl GridController { symbol: None, }; Ok(serde_wasm_bindgen::to_value( - &self.set_cell_numeric_format(sheet_id, *rect, Some(currency), cursor), + &self.set_cell_numeric_format(rect.to_sheet_rect(sheet_id), Some(currency), cursor), )?) } @@ -132,7 +135,7 @@ impl GridController { symbol: None, }; Ok(serde_wasm_bindgen::to_value( - &self.set_cell_numeric_format(sheet_id, *rect, Some(exponential), cursor), + &self.set_cell_numeric_format(rect.to_sheet_rect(sheet_id), Some(exponential), cursor), )?) } @@ -148,9 +151,11 @@ impl GridController { cursor: Option, ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); - Ok(serde_wasm_bindgen::to_value( - &self.toggle_commas(sheet_id, source, rect, cursor), - )?) + Ok(serde_wasm_bindgen::to_value(&self.toggle_commas( + source.to_sheet_pos(sheet_id), + rect.to_sheet_rect(sheet_id), + cursor, + ))?) } /// Sets cell bold formatting given as an optional [`bool`]. @@ -166,9 +171,11 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); let value: Option = serde_wasm_bindgen::from_value(bold).unwrap(); - Ok(serde_wasm_bindgen::to_value( - &self.set_cell_bold(sheet_id, *rect, value, cursor), - )?) + Ok(serde_wasm_bindgen::to_value(&self.set_cell_bold( + rect.to_sheet_rect(sheet_id), + value, + cursor, + ))?) } /// Sets cell italic formatting given as an optional [`bool`]. /// @@ -183,9 +190,11 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); let value: Option = serde_wasm_bindgen::from_value(italic).unwrap(); - Ok(serde_wasm_bindgen::to_value( - &self.set_cell_italic(sheet_id, *rect, value, cursor), - )?) + Ok(serde_wasm_bindgen::to_value(&self.set_cell_italic( + rect.to_sheet_rect(sheet_id), + value, + cursor, + ))?) } /// Sets cell text color given as an optional [`String`]. @@ -201,9 +210,11 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); let value: Option = serde_wasm_bindgen::from_value(text_color).unwrap(); - Ok(serde_wasm_bindgen::to_value( - &self.set_cell_text_color(sheet_id, *rect, value, cursor), - )?) + Ok(serde_wasm_bindgen::to_value(&self.set_cell_text_color( + rect.to_sheet_rect(sheet_id), + value, + cursor, + ))?) } /// Sets cell fill color given as an optional [`String`]. @@ -219,9 +230,11 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); let value: Option = serde_wasm_bindgen::from_value(fill_color).unwrap(); - Ok(serde_wasm_bindgen::to_value( - &self.set_cell_fill_color(sheet_id, *rect, value, cursor), - )?) + Ok(serde_wasm_bindgen::to_value(&self.set_cell_fill_color( + rect.to_sheet_rect(sheet_id), + value, + cursor, + ))?) } /// Sets cell render size (used for Html-style cells). @@ -245,9 +258,11 @@ impl GridController { } else { None }; - Ok(serde_wasm_bindgen::to_value( - &self.set_cell_render_size(sheet_id, *rect, value, cursor), - )?) + Ok(serde_wasm_bindgen::to_value(&self.set_cell_render_size( + rect.to_sheet_rect(sheet_id), + value, + cursor, + ))?) } /// Changes cell numeric decimals. @@ -264,7 +279,10 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); Ok(serde_wasm_bindgen::to_value(&self.change_decimal_places( - sheet_id, source, *rect, delta, cursor, + source.to_sheet_pos(sheet_id), + rect.to_sheet_rect(sheet_id), + delta, + cursor, ))?) } @@ -278,7 +296,7 @@ impl GridController { ) -> Result { let sheet_id = SheetId::from_str(&sheet_id).unwrap(); Ok(serde_wasm_bindgen::to_value( - &self.clear_formatting(sheet_id, rect, cursor), + &self.clear_formatting(rect.to_sheet_rect(sheet_id), cursor), )?) } } diff --git a/quadratic-core/src/wasm_bindings/controller/mod.rs b/quadratic-core/src/wasm_bindings/controller/mod.rs index 1fa33947a7..33d5e04531 100644 --- a/quadratic-core/src/wasm_bindings/controller/mod.rs +++ b/quadratic-core/src/wasm_bindings/controller/mod.rs @@ -79,12 +79,9 @@ impl GridController { #[wasm_bindgen(js_name = "getCalculationTransactionSummary")] pub fn js_calculation_transaction_summary(&mut self) -> Result { - self.updated_bounds_in_transaction(); - if let Some(summary) = self.transaction_summary() { - Ok(serde_wasm_bindgen::to_value(&summary)?) - } else { - Err(JsValue::UNDEFINED) - } + self.transaction_updated_bounds(); + let summary = self.prepare_transaction_summary(); + Ok(serde_wasm_bindgen::to_value(&summary)?) } #[wasm_bindgen(js_name = "calculationGetCells")] @@ -95,6 +92,13 @@ impl GridController { self.calculation_get_cells(get_cells) } + #[wasm_bindgen(js_name = "multiplayerTransaction")] + pub fn js_multiplayer_transaction(&mut self, operations: String) -> Result { + Ok(serde_wasm_bindgen::to_value( + &self.received_transaction(operations), + )?) + } + /// Populates a portion of a sheet with random float values. /// /// Returns a [`TransactionSummary`]. @@ -117,6 +121,7 @@ impl GridController { save: false, generate_thumbnail: false, transaction_busy: false, + forward_operations: None, html: HashSet::new(), })?) } diff --git a/quadratic-core/src/wasm_bindings/controller/summarize.rs b/quadratic-core/src/wasm_bindings/controller/summarize.rs index 5375b18105..aadce3ebc8 100644 --- a/quadratic-core/src/wasm_bindings/controller/summarize.rs +++ b/quadratic-core/src/wasm_bindings/controller/summarize.rs @@ -72,12 +72,12 @@ impl GridController { mod tests { // create a test grid and test that the summarize function works use crate::wasm_bindings::GridController; - use crate::{Pos, Rect}; + use crate::{Pos, Rect, SheetPos}; // TODO(ddimaria): move to a shared util fn set_value(gc: &mut GridController, x: i64, y: i64, value: &str) { let sheet_id = gc.sheet_ids()[0]; - gc.set_cell_value(sheet_id, Pos { x, y }, String::from(value), None); + gc.set_cell_value(SheetPos { x, y, sheet_id }, String::from(value), None); } #[test] diff --git a/quadratic-core/src/wasm_bindings/mod.rs b/quadratic-core/src/wasm_bindings/mod.rs index d09126eae1..f60adb6262 100644 --- a/quadratic-core/src/wasm_bindings/mod.rs +++ b/quadratic-core/src/wasm_bindings/mod.rs @@ -34,27 +34,27 @@ pub fn column_from_name(s: &str) -> Option { Some(util::column_from_name(s)? as f64) } -#[derive(Serialize, Deserialize, Debug, Default, Clone, TS)] -pub struct JsCodeResult { - pub cells_accessed: Vec<[i64; 2]>, - pub formatted_code: Option, - pub success: bool, - pub error_span: Option<[u32; 2]>, - pub error_msg: Option, - pub input_python_std_out: Option, - pub output_value: Option, - pub array_output: Option>>, - pub cancel_compute: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone, TS)] -pub struct JsComputeResult { - pub complete: bool, - pub rect: Option, - pub sheet_id: Option, - pub line_number: Option, - pub result: Option, -} +// #[derive(Serialize, Deserialize, Debug, Default, Clone, TS)] +// pub struct JsCodeResult { +// pub success: bool, +// pub formatted_code: Option, +// pub error_msg: Option, +// pub input_python_std_out: Option, +// pub output_value: Option, +// pub array_output: Option>>, +// pub cells_accessed: Vec<[i64; 2]>, +// pub error_span: Option<[u32; 2]>, +// pub cancel_compute: Option, +// } + +// #[derive(Serialize, Deserialize, Debug, Clone, TS)] +// pub struct JsComputeResult { +// pub complete: bool, +// pub rect: Option, +// pub sheet_id: Option, +// pub line_number: Option, +// pub result: Option, +// } #[derive(Serialize, Deserialize, Debug, Default, Clone, TS)] pub struct JsFormulaParseResult { diff --git a/quadratic-multiplayer/.env.example b/quadratic-multiplayer/.env.example index b3e300da42..3ef74fe61b 100644 --- a/quadratic-multiplayer/.env.example +++ b/quadratic-multiplayer/.env.example @@ -1,2 +1,6 @@ HOST=127.0.0.1 -PORT=3001 \ No newline at end of file +PORT=3001 +AUTH0_JWKS_URI= +AUTHENTICATE_JWT=false +HEARTBEAT_CHECK_S=15 +HEARTBEAT_TIMEOUT_S=60 \ No newline at end of file diff --git a/quadratic-multiplayer/.env.test b/quadratic-multiplayer/.env.test index b3e300da42..3ef74fe61b 100644 --- a/quadratic-multiplayer/.env.test +++ b/quadratic-multiplayer/.env.test @@ -1,2 +1,6 @@ HOST=127.0.0.1 -PORT=3001 \ No newline at end of file +PORT=3001 +AUTH0_JWKS_URI= +AUTHENTICATE_JWT=false +HEARTBEAT_CHECK_S=15 +HEARTBEAT_TIMEOUT_S=60 \ No newline at end of file diff --git a/quadratic-multiplayer/Cargo.lock b/quadratic-multiplayer/Cargo.lock index fd84287f69..76308a5dc2 100644 --- a/quadratic-multiplayer/Cargo.lock +++ b/quadratic-multiplayer/Cargo.lock @@ -26,6 +26,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anyhow" version = "1.0.75" @@ -61,9 +76,9 @@ dependencies = [ "bytes", "futures-util", "http 1.0.0", - "http-body", + "http-body 1.0.0", "http-body-util", - "hyper", + "hyper 1.0.1", "hyper-util", "itoa", "matchit", @@ -95,7 +110,7 @@ dependencies = [ "bytes", "futures-util", "http 1.0.0", - "http-body", + "http-body 1.0.0", "http-body-util", "mime", "pin-project-lite", @@ -117,7 +132,7 @@ dependencies = [ "futures-util", "headers", "http 1.0.0", - "http-body", + "http-body 1.0.0", "http-body-util", "mime", "pin-project-lite", @@ -169,6 +184,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + [[package]] name = "byteorder" version = "1.5.0" @@ -196,6 +217,37 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.48.5", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpufeatures" version = "0.2.11" @@ -256,6 +308,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +[[package]] +name = "deranged" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +dependencies = [ + "powerfmt", +] + [[package]] name = "deunicode" version = "1.4.1" @@ -290,6 +351,15 @@ dependencies = [ "syn", ] +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + [[package]] name = "envy" version = "0.4.2" @@ -305,6 +375,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "fake" version = "2.9.1" @@ -316,12 +396,33 @@ dependencies = [ "rand", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -437,8 +538,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -447,6 +550,25 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "h2" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.11", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.0" @@ -524,6 +646,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http 0.2.11", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.0" @@ -543,7 +676,7 @@ dependencies = [ "bytes", "futures-util", "http 1.0.0", - "http-body", + "http-body 1.0.0", "pin-project-lite", ] @@ -565,6 +698,30 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.22", + "http 0.2.11", + "http-body 0.4.5", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.0.1" @@ -574,9 +731,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", + "h2 0.4.0", "http 1.0.0", - "http-body", + "http-body 1.0.0", "httparse", "httpdate", "itoa", @@ -584,6 +741,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.27", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "hyper-util" version = "0.1.1" @@ -594,16 +764,39 @@ dependencies = [ "futures-channel", "futures-util", "http 1.0.0", - "http-body", - "hyper", + "http-body 1.0.0", + "hyper 1.0.1", "pin-project-lite", - "socket2", + "socket2 0.5.5", "tokio", "tower", "tower-service", "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -630,12 +823,42 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" +dependencies = [ + "base64", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -648,6 +871,12 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + [[package]] name = "lock_api" version = "0.4.11" @@ -718,7 +947,25 @@ checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] @@ -731,6 +978,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -756,6 +1033,50 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "openssl" +version = "0.10.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "overload" version = "0.1.1" @@ -782,7 +1103,17 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "pem" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923" +dependencies = [ + "base64", + "serde", ] [[package]] @@ -823,6 +1154,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -845,12 +1188,15 @@ dependencies = [ "anyhow", "axum", "axum-extra", + "chrono", "dotenv", "envy", "fake", "futures", "futures-util", "headers", + "jsonwebtoken", + "reqwest", "serde", "serde_json", "tokio", @@ -954,12 +1300,77 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.22", + "http 0.2.11", + "http-body 0.4.5", + "hyper 0.14.27", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.48.0", +] + [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustix" +version = "0.38.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -972,12 +1383,44 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.193" @@ -1060,6 +1503,18 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + [[package]] name = "slab" version = "0.4.9" @@ -1075,6 +1530,16 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.5" @@ -1082,9 +1547,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "strsim" version = "0.10.0" @@ -1108,6 +1579,40 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" version = "1.0.50" @@ -1138,6 +1643,35 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1167,9 +1701,9 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1183,6 +1717,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-tungstenite" version = "0.20.1" @@ -1235,7 +1779,7 @@ dependencies = [ "bytes", "futures-util", "http 1.0.0", - "http-body", + "http-body 1.0.0", "http-body-util", "http-range-header", "httpdate", @@ -1324,6 +1868,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "tungstenite" version = "0.20.1" @@ -1379,6 +1929,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.0" @@ -1412,18 +1968,109 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1446,13 +2093,31 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -1461,13 +2126,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -1476,38 +2156,90 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] diff --git a/quadratic-multiplayer/Cargo.toml b/quadratic-multiplayer/Cargo.toml index 35660f7b5c..5cd7979b3b 100644 --- a/quadratic-multiplayer/Cargo.toml +++ b/quadratic-multiplayer/Cargo.toml @@ -8,11 +8,16 @@ authors = ["David DiMaria "] anyhow = "1.0.75" axum = { version = "0.7.1", features = ["ws"] } axum-extra = { version = "0.9.0", features = ["typed-header"] } +chrono = { version= "0.4.31", features = ["serde"] } dotenv = "0.15.0" envy = "0.4.2" futures = "0.3.29" futures-util = { version = "0.3.29", default-features = false, features = ["sink", "std"] } headers = "0.4.0" +jsonwebtoken = "9.2.0" +quadratic-core = { path = "../quadratic-core" } +reqwest = { version = "0.11.22", features = ["json", "serde_json"] } +rust-shared = { path = "../rust-shared" } serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" tokio = { version = "1.34.0", features = ["full"] } @@ -25,3 +30,4 @@ uuid = { version = "1.6.1", features = ["serde", "v4"] } [dev-dependencies] fake = { version = "2.9.1", features = ["derive"] } +mockall = "0.12.0" diff --git a/quadratic-multiplayer/README.md b/quadratic-multiplayer/README.md index 6f6139180a..309621fa78 100644 --- a/quadratic-multiplayer/README.md +++ b/quadratic-multiplayer/README.md @@ -68,17 +68,6 @@ Signals that a user has entered the room #### Request -```rust -EnterRoom { - r#type: String, - user_id: Uuid, - file_id: Uuid, - first_name: String, - last_name: String, - image: String, -}, -``` - JSON: ```json @@ -94,23 +83,6 @@ JSON: #### Response -```rust -User { - id: Uuid, - first_name: String, - last_name: String, - image: String, -} - -Room { - r#type: String, - room: { - file_id: Uuid, - users: HashMap, - }, -}, -``` - JSON: ```json @@ -134,23 +106,48 @@ JSON: } ``` -### MouseMove +### Leave Room -Signals that a user in a room moved their mouse. +Signals that a user leaves a room #### Request -Rust: +JSON: + +```json +{ + "type": "LeaveRoom", + "user_id": "00000000-0000-0000-0000-000000000000", + "file_id": "00000000-0000-0000-0000-000000000001" +} +``` + +#### Response + +JSON: -```rust -MouseMove { - user_id: Uuid, - file_id: Uuid, - x: f64, - y: f64, -}, +```json +{ + "type":"Room", + "room":{ + "file_id":"00000000-0000-0000-0000-000000000001", + "users":{ + "00000000-0000-0000-0000-000000000002":{ + "first_name":"David", + "last_name":"Figatner", + "image":"https://lh3.googleusercontent.com/a/ACg8ocLcJuKVkU7-Zr67hinRLyzgO_o3VOeMlOA17HcOlKe1fQ=s96-c" + } + } + } +} ``` +### MouseMove + +Signals that a user in a room moved their mouse. + +#### Request + JSON: ```json @@ -165,17 +162,6 @@ JSON: #### Response -Rust: - -```rust -MouseMove { - user_id: Uuid, - file_id: Uuid, - x: f64, - y: f64, -}, -``` - JSON: ```json @@ -187,3 +173,28 @@ JSON: "y": 10 } ``` + + +### Heartbeat + +Signals that a user is still active in a room + +#### Request + +JSON: + +```json +{ + "type": "Heartbeat", + "user_id": "00000000-0000-0000-0000-000000000000", + "file_id": "00000000-0000-0000-0000-000000000001", +} +``` + +#### Response + +JSON: + +```json +{} +``` diff --git a/quadratic-multiplayer/app.json b/quadratic-multiplayer/app.json new file mode 100644 index 0000000000..2faa180a9a --- /dev/null +++ b/quadratic-multiplayer/app.json @@ -0,0 +1,7 @@ +{ + "buildpacks": [ + { + "url": "https://github.com/ph3nx/heroku-binary-buildpack.git" + } + ] +} diff --git a/quadratic-multiplayer/package.json b/quadratic-multiplayer/package.json index be8a0ae141..ca2a532cd7 100644 --- a/quadratic-multiplayer/package.json +++ b/quadratic-multiplayer/package.json @@ -11,9 +11,9 @@ "test": "cargo test", "test:watch": "RUST_LOG=info cargo watch -x 'test'", "lint": "cargo clippy --all-targets --all-features -- -D warnings", + "coverage": "npm run coverage:gen && npm run coverage:html && npm run coverage:view", "coverage:gen": "CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' LLVM_PROFILE_FILE='coverage/cargo-test-%p-%m.profraw' cargo test", - "coverage:html": "grcov . --binary-path ./target/debug/deps/ -s . -t html --branch --ignore-not-existing --ignore 'src/main.rs' -o coverage/html", + "coverage:html": "grcov . --binary-path ./target/debug/deps/ -s . -t html --branch --ignore-not-existing --ignore '../*' --ignore '/*' -o coverage/html", "coverage:view": "open coverage/html/index.html" - } } diff --git a/quadratic-multiplayer/src/auth.rs b/quadratic-multiplayer/src/auth.rs new file mode 100644 index 0000000000..3a22f8eb29 --- /dev/null +++ b/quadratic-multiplayer/src/auth.rs @@ -0,0 +1,82 @@ +use anyhow::{anyhow, bail, Result}; +use jsonwebtoken::jwk::AlgorithmParameters; +use jsonwebtoken::{decode, decode_header, jwk, Algorithm, DecodingKey, TokenData, Validation}; +use std::collections::HashMap; +use std::str::FromStr; + +/// Get the JWK set from a given URL. +pub(crate) async fn get_jwks(url: &str) -> Result { + let jwks = reqwest::get(url).await?.json::().await?; + + Ok(jwks) +} + +/// Authorize a JWT token using a given JWK set. +pub(crate) fn authorize( + jwks: &jwk::JwkSet, + token: &str, + validate_aud: bool, + validate_exp: bool, +) -> Result>> { + let header = decode_header(token)?; + let decoded_token; + let kid = header + .kid + .ok_or_else(|| anyhow!("Token doesn't have a `kid` header field"))?; + + // Validate the JWT using an algorithm. The algorithm needs to be RSA. + if let Some(jwk) = jwks.find(&kid) { + match &jwk.algorithm { + AlgorithmParameters::RSA(rsa) => { + let decoding_key = DecodingKey::from_rsa_components(&rsa.n, &rsa.e)?; + let key_algorithm = jwk + .common + .key_algorithm + .ok_or_else(|| anyhow!("Invalid key algorithm"))? + .to_string(); + + let mut validation = Validation::new(Algorithm::from_str(&key_algorithm)?); + validation.validate_exp = validate_exp; + validation.validate_aud = validate_aud; + + decoded_token = decode::>( + token, + &decoding_key, + &validation, + )?; + } + _ => bail!("Unsupported algorithm, should be RSA"), + } + } else { + bail!("No matching JWK found for the given kid"); + } + + Ok(decoded_token) +} + +#[cfg(test)] +pub(crate) mod tests { + use crate::test_util::assert_anyhow_error; + + use super::*; + + const TOKEN: &str = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjFaNTdkX2k3VEU2S1RZNTdwS3pEeSJ9.eyJpc3MiOiJodHRwczovL2Rldi1kdXp5YXlrNC5ldS5hdXRoMC5jb20vIiwic3ViIjoiNDNxbW44c281R3VFU0U1N0Fkb3BhN09jYTZXeVNidmRAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZGV2LWR1enlheWs0LmV1LmF1dGgwLmNvbS9hcGkvdjIvIiwiaWF0IjoxNjIzNTg1MzAxLCJleHAiOjE2MjM2NzE3MDEsImF6cCI6IjQzcW1uOHNvNUd1RVNFNTdBZG9wYTdPY2E2V3lTYnZkIiwic2NvcGUiOiJyZWFkOnVzZXJzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.0MpewU1GgvRqn4F8fK_-Eu70cUgWA5JJrdbJhkCPCxXP-8WwfI-qx1ZQg2a7nbjXICYAEl-Z6z4opgy-H5fn35wGP0wywDqZpqL35IPqx6d0wRvpPMjJM75zVXuIjk7cEhDr2kaf1LOY9auWUwGzPiDB_wM-R0uvUMeRPMfrHaVN73xhAuQWVjCRBHvNscYS5-i6qBQKDMsql87dwR72DgHzMlaC8NnaGREBC-xiSamesqhKPVyGzSkFSaF3ZKpGrSDapqmHkNW9RDBE3GQ9OHM33vzUdVKOjU1g9Leb9PDt0o1U4p3NQoGJPShQ6zgWSUEaqvUZTfkbpD_DoYDRxA"; + const JWKS: &str = r#" +{"keys":[{"alg":"RS256","kty":"RSA","use":"sig","n":"2V31IZF-EY2GxXQPI5OaEE--sezizPamNZDW9AjBE2cCErfufM312nT2jUsCnfjsXnh6Z_b-ncOMr97zIZkq1ofU7avemv8nX7NpKmoPBpVrMPprOax2-e3wt-bSfFLIHyghjFLKpkT0LOL_Fimi7xY-J86R06WHojLo3yGzAgQCswZmD4CFf6NcBWDcb6l6kx5vk_AdzHIkVEZH4aikUL_fn3zq5qbE25oOg6pT7F7Pp4zdHOAEKnIRS8tvP8tvvVRkUCrjBxz_Kx6Ne1YOD-fkIMRk_MgIWeKZZzZOYx4VrC0vqYiM-PcKWbNdt1kNoTHOeL06XZeSE6WPZ3VB1Q","e":"AQAB","kid":"1Z57d_i7TE6KTY57pKzDy","x5t":"1gA-aTE9VglLXZnrqvzwWhHsFdk","x5c":["MIIDDTCCAfWgAwIBAgIJHwhLfcIbNvmkMA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMTGWRldi1kdXp5YXlrNC5ldS5hdXRoMC5jb20wHhcNMjEwNjEzMDcxMTQ1WhcNMzUwMjIwMDcxMTQ1WjAkMSIwIAYDVQQDExlkZXYtZHV6eWF5azQuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2V31IZF+EY2GxXQPI5OaEE++sezizPamNZDW9AjBE2cCErfufM312nT2jUsCnfjsXnh6Z/b+ncOMr97zIZkq1ofU7avemv8nX7NpKmoPBpVrMPprOax2+e3wt+bSfFLIHyghjFLKpkT0LOL/Fimi7xY+J86R06WHojLo3yGzAgQCswZmD4CFf6NcBWDcb6l6kx5vk/AdzHIkVEZH4aikUL/fn3zq5qbE25oOg6pT7F7Pp4zdHOAEKnIRS8tvP8tvvVRkUCrjBxz/Kx6Ne1YOD+fkIMRk/MgIWeKZZzZOYx4VrC0vqYiM+PcKWbNdt1kNoTHOeL06XZeSE6WPZ3VB1QIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRPX3shmtgajnR4ly5t9VYB66ufGDAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAHtKpX70WU4uXOMjbFKj0e9HMXyCrdcX6TuYiMFqqlOGWM4yghSM8Bd0HkKcirm4DUoC+1dDMzXMZ+tbntavPt1xG0eRFjeocP+kIYTMQEG2LDM5HQ+Z7bdcwlxnuYOZQfpgKAfYbQ8Cxu38sB6q82I+5NJ0w0VXuG7nUZ1RD+rkXaeMYHNoibAtKBoTWrCaFWGV0E55OM+H0ckcHKUUnNXJOyZ+zEOzPFY5iuYIUmn1LfR1P0SLgIMfiooNC5ZuR/wLdbtyKtor2vzz7niEiewz+aPvfuPnWe/vMtQrfS37/yEhCozFnbIps/+S2Ay78mNBDuOAA9fg5yrnOmjABCU="]},{"alg":"RS256","kty":"RSA","use":"sig","n":"0KDpAuJZyDwPg9CfKi0R3QwDROyH0rvd39lmAoqQNqtYPghDToxFMDLpul0QHttbofHPJMKrPfeEFEOvw7KJgelCHZmckVKaz0e4tfu_2Uvw2kFljCmJGfspUU3mXxLyEea9Ef9JqUru6L8f_0_JIDMT3dceqU5ZqbG8u6-HRgRQ5Jqc_fF29Xyw3gxNP_Q46nsp_0yE68UZE1iPy1om0mpu8mpsY1-Nbvm51C8i4_tFQHdUXbhF4cjAoR0gZFNkzr7FCrL4On0hKeLcvxIHD17SxaBsTuCBGd35g7TmXsA4hSimD9taRHA-SkXh558JG5dr-YV9x80qjeSAvTyjcQ","e":"AQAB","kid":"v2HFn4VqJB-U4vtQRJ3Ql","x5t":"AhUBZjtsFdx7C1PFtWAJ756bo5k","x5c":["MIIDDTCCAfWgAwIBAgIJSSFLkuG8uAM8MA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMTGWRldi1kdXp5YXlrNC5ldS5hdXRoMC5jb20wHhcNMjEwNjEzMDcxMTQ2WhcNMzUwMjIwMDcxMTQ2WjAkMSIwIAYDVQQDExlkZXYtZHV6eWF5azQuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0KDpAuJZyDwPg9CfKi0R3QwDROyH0rvd39lmAoqQNqtYPghDToxFMDLpul0QHttbofHPJMKrPfeEFEOvw7KJgelCHZmckVKaz0e4tfu/2Uvw2kFljCmJGfspUU3mXxLyEea9Ef9JqUru6L8f/0/JIDMT3dceqU5ZqbG8u6+HRgRQ5Jqc/fF29Xyw3gxNP/Q46nsp/0yE68UZE1iPy1om0mpu8mpsY1+Nbvm51C8i4/tFQHdUXbhF4cjAoR0gZFNkzr7FCrL4On0hKeLcvxIHD17SxaBsTuCBGd35g7TmXsA4hSimD9taRHA+SkXh558JG5dr+YV9x80qjeSAvTyjcQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSEkRwvkyYzzzY/jPd1n7/1VRQNdzAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAGtdl7QwzpaWZjbmd6UINAIlpuWIo2v4EJD9kGan/tUZTiUdBaJVwFHOkLRsbZHc5PmBB5IryjOcrqsmKvFdo6wUZA92qTuQVZrOTea07msOKSWE6yRUh1/VCXH2+vAiB9A4DFZ23WpZikBR+DmiD8NGwVgAwWw9jM6pe7ODY+qxFXGjQdTCHcDdbqG2160nKEHCBvjR1Sc/F0pzHPv8CBJCyGAPTCXX42sKZI92pPzdKSmNNijCuIEYLsjzKVxaUuwEqIshk3mYeu6im4VmXXFj+MlyMsusVWi2py7fGFadamzyiV/bxZe+4xzzrRG1Kow/WnVEizfTdEzFXO6YikE="]}]} +"#; + + #[tokio::test] + async fn test_authorize() { + let jwks: jwk::JwkSet = serde_json::from_str(JWKS).unwrap(); + let result = authorize(&jwks, TOKEN, false, false); + assert!(result.is_ok()); + + // invalid audience causes error + let result = authorize(&jwks, TOKEN, true, false); + assert_anyhow_error(result, "InvalidAudience"); + + // past expiration causes error + let result = authorize(&jwks, TOKEN, false, true); + assert_anyhow_error(result, "ExpiredSignature"); + } +} diff --git a/quadratic-multiplayer/src/background_worker.rs b/quadratic-multiplayer/src/background_worker.rs new file mode 100644 index 0000000000..eb864f07f7 --- /dev/null +++ b/quadratic-multiplayer/src/background_worker.rs @@ -0,0 +1,141 @@ +use anyhow::{anyhow, Result}; +use std::{sync::Arc, time::Duration}; +use tokio::{task::JoinHandle, time}; +use uuid::Uuid; + +use crate::{ + message::{broadcast, response::MessageResponse}, + state::{room::Room, State}, +}; + +/// In a separate thread: +/// * Broadcast sequence number to all users in the room +/// * Check for stale users in rooms and remove them. +#[tracing::instrument(level = "trace")] +pub(crate) async fn start(state: Arc, heartbeat_check_s: i64, heartbeat_timeout_s: i64) { + let state = Arc::clone(&state); + + tokio::spawn(async move { + let mut interval = time::interval(Duration::from_millis(heartbeat_check_s as u64 * 1000)); + let rooms = state.rooms.lock().await.clone(); + + loop { + for (file_id, room) in rooms.iter() { + // broadcast sequence number to all users in the room + if let Err(error) = + broadcast_sequence_num(Arc::clone(&state), file_id.to_owned()).await + { + tracing::warn!("Error broadcasting sequence number: {:?}", error); + } + + // remove stale users in the room + if let Err(error) = remove_stale_users_in_room( + Arc::clone(&state), + file_id, + room, + heartbeat_timeout_s, + ) + .await + { + tracing::warn!( + "Error removing stale users from room {file_id}: {:?}", + error + ); + } + } + + interval.tick().await; + } + }); +} + +// broadcast sequence number to all users in the room +async fn broadcast_sequence_num(state: Arc, file_id: Uuid) -> Result> { + let sequence_num = state + .transaction_queue + .lock() + .await + .get_sequence_num(file_id.to_owned())?; + + Ok(broadcast( + vec![], + file_id.to_owned(), + Arc::clone(&state), + MessageResponse::CurrentTransaction { sequence_num }, + )) +} + +// remove stale users in the room +#[tracing::instrument(level = "trace")] +async fn remove_stale_users_in_room( + state: Arc, + file_id: &Uuid, + room: &Room, + heartbeat_timeout_s: i64, +) -> Result> { + let (num_removed, num_remaining) = state + .remove_stale_users_in_room(file_id.to_owned(), heartbeat_timeout_s) + .await?; + + tracing::info!("Checking heartbeats in room {file_id} ({num_remaining} remaining in room)"); + + if num_removed > 0 { + return Ok(broadcast( + vec![], + file_id.to_owned(), + Arc::clone(&state), + MessageResponse::from(room.to_owned()), + )); + } + + Err(anyhow!("Error removing stale users from room {file_id}")) +} + +#[cfg(test)] +mod tests { + use crate::test_util::{add_new_user_to_room, grid_setup, operation}; + + use super::*; + + #[tokio::test] + async fn broadcast_sequence_num() { + let state = Arc::new(State::new()); + let file_id = Uuid::new_v4(); + let mut grid = grid_setup(); + let transaction_id_1 = Uuid::new_v4(); + let operations_1 = operation(&mut grid, 0, 0, "1"); + + state.transaction_queue.lock().await.push( + transaction_id_1, + file_id, + vec![operations_1.clone()], + ); + + super::broadcast_sequence_num(state, file_id) + .await + .unwrap() + .await + .unwrap(); + } + + #[tokio::test] + async fn remove_stale_users_in_room() { + let state = Arc::new(State::new()); + let file_id = Uuid::new_v4(); + let connection_id = Uuid::new_v4(); + let user = add_new_user_to_room(file_id, state.clone(), connection_id).await; + + let room = state.get_room(&file_id).await.unwrap(); + assert_eq!(room.users.get(&user.session_id), Some(&user)); + + super::remove_stale_users_in_room(state.clone(), &file_id, &room, -1) + .await + .unwrap() + .await + .unwrap(); + + // user was removed from the room and the room was closed + let room = state.get_room(&file_id).await; + assert!(room.is_err()); + } +} diff --git a/quadratic-multiplayer/src/config.rs b/quadratic-multiplayer/src/config.rs index 7255229972..828e0f5f08 100644 --- a/quadratic-multiplayer/src/config.rs +++ b/quadratic-multiplayer/src/config.rs @@ -13,6 +13,10 @@ use serde::Deserialize; pub(crate) struct Config { pub(crate) host: String, pub(crate) port: String, + pub(crate) auth0_jwks_uri: String, + pub(crate) heartbeat_check_s: i64, + pub(crate) heartbeat_timeout_s: i64, + pub(crate) authenticate_jwt: bool, } /// Load the global configuration from the environment into Config. diff --git a/quadratic-multiplayer/src/file.rs b/quadratic-multiplayer/src/file.rs new file mode 100644 index 0000000000..fbd868fc5c --- /dev/null +++ b/quadratic-multiplayer/src/file.rs @@ -0,0 +1,60 @@ +use anyhow::Result; +use quadratic_core::{ + controller::{ + operations::operation::Operation, transaction_summary::TransactionSummary, GridController, + }, + grid::{file::import, Grid}, +}; + +/// Load a .grid file +pub(crate) fn _load_file(file: &str) -> Result { + import(file) +} + +/// Apply a stringified vec of operations to the grid +pub(crate) fn _apply_string_operations( + grid: &mut GridController, + operations: String, +) -> Result { + let operations: Vec = serde_json::from_str(&operations)?; + + _apply_operations(grid, operations) +} + +/// Apply a vec of operations to the grid +pub(crate) fn _apply_operations( + grid: &mut GridController, + operations: Vec, +) -> Result { + Ok(grid.apply_received_transaction(operations)) +} + +#[cfg(test)] +mod tests { + use quadratic_core::test_util::assert_cell_value; + use quadratic_core::{Array, CellValue, SheetPos}; + + use super::*; + + #[test] + fn loads_a_file() { + let file = + _load_file(include_str!("../../rust-shared/data/grid/v1_4_simple.grid")).unwrap(); + + let mut grid = GridController::from_grid(file); + let sheet_id = grid.sheet_ids().first().unwrap().to_owned(); + let sheet_rect = SheetPos { + x: 0, + y: 0, + sheet_id, + } + .into(); + let value = CellValue::Text("hello".to_string()); + let values = Array::from(value); + let operation = Operation::SetCellValues { sheet_rect, values }; + + let _ = _apply_operations(&mut grid, vec![operation]); + + assert_cell_value(&grid, sheet_id, 0, 0, "hello"); + } +} diff --git a/quadratic-multiplayer/src/main.rs b/quadratic-multiplayer/src/main.rs index 381bc51d65..fb0a12c4fc 100644 --- a/quadratic-multiplayer/src/main.rs +++ b/quadratic-multiplayer/src/main.rs @@ -3,7 +3,10 @@ //! A multiplayer server for Quadratic. Supports user presence and mouse //! tracking for a shared file. +mod auth; +mod background_worker; mod config; +mod file; mod message; mod server; mod state; diff --git a/quadratic-multiplayer/src/message.rs b/quadratic-multiplayer/src/message.rs deleted file mode 100644 index e13f94f317..0000000000 --- a/quadratic-multiplayer/src/message.rs +++ /dev/null @@ -1,263 +0,0 @@ -//! Websocket Message Handler -//! -//! A central place for handling websocket messages. This module is -//! responsible for incoming requests and outgoing responses. Since -//! socket information is stored in the global state, we can broadcast -//! to all users in a room. - -use std::sync::Arc; - -use anyhow::Result; -use axum::extract::ws::{Message, WebSocket}; -use futures_util::stream::SplitSink; -use futures_util::SinkExt; -use serde::{Deserialize, Serialize}; -use tokio::sync::Mutex; -use uuid::Uuid; - -use crate::state::{Room, State, User}; - -// NOTE: needs to be kept in sync with multiplayerTypes.ts -#[derive(Serialize, Deserialize, Debug, PartialEq)] -#[serde(tag = "type")] -pub(crate) enum MessageRequest { - EnterRoom { - user_id: String, - file_id: Uuid, - first_name: String, - last_name: String, - image: String, - }, - MouseMove { - user_id: String, - file_id: Uuid, - x: Option, - y: Option, - }, - ChangeSelection { - user_id: String, - file_id: Uuid, - selection: String, - }, - Transaction { - user_id: String, - file_id: Uuid, - - // todo: this is a stringified Vec. Eventually, Operation should be a shared type. - operations: String, - }, -} - -// NOTE: needs to be kept in sync with multiplayerTypes.ts -#[derive(Serialize, Debug, Clone, PartialEq)] -#[serde(tag = "type")] -pub(crate) enum MessageResponse { - Room { - room: Room, - }, - MouseMove { - user_id: String, - file_id: Uuid, - x: Option, - y: Option, - }, - ChangeSelection { - user_id: String, - file_id: Uuid, - selection: String, - }, - Transaction { - user_id: String, - file_id: Uuid, - - // todo: this is a stringified Vec. Eventually, Operation should be a shared type. - operations: String, - }, -} - -/// Handle incoming messages. All requests and responses are strictly typed. -pub(crate) async fn handle_message( - request: MessageRequest, - state: Arc, - sender: Arc>>, -) -> Result { - tracing::trace!("Handling message {:?}", request); - - match request { - // User enters a room. - MessageRequest::EnterRoom { - user_id, - file_id, - first_name, - last_name, - image, - } => { - let user = User { - id: user_id, - first_name, - last_name, - image, - socket: Some(Arc::clone(&sender)), - }; - let user_id = user.id.clone(); - let is_new = state.enter_room(file_id, &user).await; - let room = state.get_room(&file_id).await?; - let response = MessageResponse::Room { room }; - tracing::info!("user {} entered room", user.id); - - // only broadcast if the user is new to the room - if is_new { - broadcast(user_id, file_id, Arc::clone(&state), response.clone())?; - } - - Ok(response) - } - - // User moves their mouse - MessageRequest::MouseMove { - user_id, - file_id, - x, - y, - } => { - let response = MessageResponse::MouseMove { - user_id: user_id.clone(), - file_id, - x, - y, - }; - - broadcast(user_id, file_id, Arc::clone(&state), response.clone())?; - - Ok(response) - } - - // User changes their selection - MessageRequest::ChangeSelection { - user_id, - file_id, - selection, - } => { - let response = MessageResponse::ChangeSelection { - user_id: user_id.clone(), - file_id, - selection, - }; - - broadcast(user_id, file_id, Arc::clone(&state), response.clone())?; - - Ok(response) - } - - // User sends transactions - MessageRequest::Transaction { - user_id, - file_id, - operations, - } => { - let response = MessageResponse::Transaction { - user_id: user_id.clone(), - file_id, - operations, - }; - - broadcast(user_id, file_id, Arc::clone(&state), response.clone())?; - - Ok(response) - } - } -} - -/// Broadcast a message to all users in a room except the sender. -/// All messages are sent in a separate thread. -pub(crate) fn broadcast( - user_id: String, - file_id: Uuid, - state: Arc, - message: MessageResponse, -) -> Result<()> { - tokio::spawn(async move { - let result = async { - for (_, user) in state - .get_room(&file_id) - .await? - .users - .iter() - // todo: this is not working :( - .filter(|(_, user)| user_id != user.id) - { - if let Some(sender) = &user.socket { - sender - .lock() - .await - .send(Message::Text(serde_json::to_string(&message)?)) - .await?; - } - } - - Ok::<_, anyhow::Error>(()) - }; - - if let Err(e) = result.await { - tracing::error!("Error broadcasting message: {:?}", e); - } - }); - - Ok(()) -} - -#[cfg(test)] -pub(crate) mod tests { - - use super::*; - use crate::test_util::add_new_user_to_room; - - #[tokio::test] - async fn test_mouse_move() { - let state = Arc::new(State::new()); - let file_id = Uuid::new_v4(); - let user_1 = add_new_user_to_room(file_id, state.clone()).await; - let _user_2 = add_new_user_to_room(file_id, state.clone()).await; - let message = MessageResponse::MouseMove { - user_id: user_1.id.clone(), - file_id, - x: Some(10f64), - y: Some(10f64), - }; - broadcast(user_1.id.clone(), file_id, state, message).unwrap(); - - // TODO(ddimaria): mock the splitsink sender to test the actual sending - } - - #[tokio::test] - async fn test_change_selection() { - let state = Arc::new(State::new()); - let file_id = Uuid::new_v4(); - let user_1 = add_new_user_to_room(file_id, state.clone()).await; - let _user_2 = add_new_user_to_room(file_id, state.clone()).await; - let message = MessageResponse::ChangeSelection { - user_id: user_1.id.clone(), - file_id: file_id, - selection: "test".to_string(), - }; - broadcast(user_1.id.clone(), file_id, state, message).unwrap(); - - // TODO(ddimaria): mock the splitsink sender to test the actual sending - } - - #[tokio::test] - async fn test_transaction() { - let state = Arc::new(State::new()); - let file_id = Uuid::new_v4(); - let user_1 = add_new_user_to_room(file_id, state.clone()).await; - let _user_2 = add_new_user_to_room(file_id, state.clone()).await; - let message = MessageResponse::Transaction { - user_id: user_1.id.clone(), - file_id: file_id, - operations: "test".to_string(), - }; - broadcast(user_1.id.clone(), file_id, state, message).unwrap(); - - // TODO(ddimaria): mock the splitsink sender to test the actual sending - } -} diff --git a/quadratic-multiplayer/src/message/handle.rs b/quadratic-multiplayer/src/message/handle.rs new file mode 100644 index 0000000000..88ccbc1a26 --- /dev/null +++ b/quadratic-multiplayer/src/message/handle.rs @@ -0,0 +1,358 @@ +//! Websocket Message Handler +//! +//! A central place for handling websocket messages. This module is +//! responsible for incoming requests and outgoing responses. Since +//! socket information is stored in the global state, we can broadcast +//! to all users in a room. + +use anyhow::Result; +use axum::extract::ws::{Message, WebSocket}; +use futures_util::stream::SplitSink; +use std::sync::Arc; +use tokio::sync::Mutex; +use uuid::Uuid; + +use crate::message::{broadcast, request::MessageRequest, response::MessageResponse}; +use crate::state::user::UserState; +use crate::state::{user::User, State}; + +/// Handle incoming messages. All requests and responses are strictly typed. +#[tracing::instrument(level = "trace")] +pub(crate) async fn handle_message( + request: MessageRequest, + state: Arc, + sender: Arc>>, + connection_id: Uuid, +) -> Result> { + tracing::trace!("Handling message {:?}", request); + + match request { + // User enters a room. + MessageRequest::EnterRoom { + session_id, + user_id, + file_id, + first_name, + last_name, + email, + image, + sheet_id, + selection, + cell_edit, + viewport, + } => { + let user_state = UserState { + sheet_id, + selection, + cell_edit, + x: 0.0, + y: 0.0, + visible: false, + viewport, + }; + + let user = User { + user_id, + session_id, + first_name, + last_name, + email, + image, + state: user_state, + socket: Some(Arc::clone(&sender)), + last_heartbeat: chrono::Utc::now(), + }; + + let is_new = state.enter_room(file_id, &user, connection_id).await; + + // only broadcast if the user is new to the room + if is_new { + let room = state.get_room(&file_id).await?; + let response = MessageResponse::from(room.to_owned()); + + broadcast(vec![], file_id, Arc::clone(&state), response); + } + + Ok(None) + } + + // User leaves a room + MessageRequest::LeaveRoom { + session_id, + file_id, + } => { + let is_not_empty = state.leave_room(file_id, &session_id).await?; + let room = state.get_room(&file_id).await?; + + if is_not_empty { + let response = MessageResponse::from(room.to_owned()); + broadcast(vec![session_id], file_id, Arc::clone(&state), response); + } + + Ok(None) + } + + // User sends transactions + MessageRequest::Transaction { + id, + session_id, + file_id, + operations, + } => { + // update the heartbeat + state.update_user_heartbeat(file_id, &session_id).await?; + + // add the transaction to the transaction queue + let sequence_num = state.transaction_queue.lock().await.push( + id, + file_id, + serde_json::from_str(&operations)?, + ); + + let response = MessageResponse::Transaction { + id, + file_id, + operations, + sequence_num, + }; + + // the user who sent the transaction should receive the transaction response + broadcast(vec![], file_id, Arc::clone(&state), response); + + Ok(None) + } + + // User sends transactions + MessageRequest::GetTransactions { + file_id, + session_id, + min_sequence_num, + } => { + // update the heartbeat + state.update_user_heartbeat(file_id, &session_id).await?; + + // get transactions from the transaction queue + let transactions = state + .transaction_queue + .lock() + .await + .get_transactions_min_sequence_num(file_id, min_sequence_num)?; + + let response = MessageResponse::Transactions { transactions }; + + Ok(Some(response)) + } + + MessageRequest::UserUpdate { + session_id, + file_id, + update, + } => { + // update the heartbeat + state.update_user_heartbeat(file_id, &session_id).await?; + + // update user state + state + .update_user_state(&file_id, &session_id, &update) + .await?; + let response = MessageResponse::UserUpdate { + session_id, + file_id, + update, + }; + + broadcast(vec![session_id], file_id, Arc::clone(&state), response); + + Ok(None) + } + + // User sends a heartbeat + MessageRequest::Heartbeat { + session_id, + file_id, + } => { + // update the heartbeat + state.update_user_heartbeat(file_id, &session_id).await?; + Ok(None) + } + } +} + +#[cfg(test)] +pub(crate) mod tests { + + use super::*; + use crate::state::user::{CellEdit, UserStateUpdate}; + use crate::test_util::add_new_user_to_room; + + async fn setup() -> (Arc, Uuid, User) { + let state = Arc::new(State::new()); + let connection_id = Uuid::new_v4(); + let file_id = Uuid::new_v4(); + let user_1 = add_new_user_to_room(file_id, state.clone(), connection_id).await; + + (state, file_id, user_1) + } + + #[tokio::test] + async fn test_update_state() { + let (state, file_id, user_1) = setup().await; + let message = MessageResponse::UserUpdate { + session_id: user_1.session_id, + file_id, + update: UserStateUpdate { + sheet_id: None, + selection: Some("selection".to_string()), + x: Some(1.0), + y: Some(2.0), + visible: Some(true), + cell_edit: None, + viewport: None, + }, + }; + broadcast(vec![user_1.session_id], file_id, state, message) + .await + .unwrap(); + + // TODO(ddimaria): mock the splitsink sender to test the actual sending + } + + #[tokio::test] + async fn test_change_selection() { + let (state, file_id, user_1) = setup().await; + let message = MessageResponse::UserUpdate { + session_id: user_1.session_id, + file_id, + update: UserStateUpdate { + selection: Some("test".to_string()), + sheet_id: None, + x: None, + y: None, + visible: None, + cell_edit: None, + viewport: None, + }, + }; + broadcast(vec![user_1.session_id], file_id, state, message) + .await + .unwrap(); + + // TODO(ddimaria): mock the splitsink sender to test the actual sending + } + + #[tokio::test] + async fn test_change_visibility() { + let (state, file_id, user_1) = setup().await; + let message = MessageResponse::UserUpdate { + session_id: user_1.session_id, + file_id, + update: UserStateUpdate { + selection: None, + sheet_id: None, + x: None, + y: None, + visible: Some(false), + cell_edit: None, + viewport: None, + }, + }; + broadcast(vec![user_1.session_id], file_id, state, message) + .await + .unwrap(); + + // TODO(ddimaria): mock the splitsink sender to test the actual sending + } + + #[tokio::test] + async fn test_change_sheet() { + let (state, file_id, user_1) = setup().await; + let message = MessageResponse::UserUpdate { + session_id: user_1.session_id, + file_id, + update: UserStateUpdate { + selection: None, + sheet_id: Some(Uuid::new_v4()), + x: None, + y: None, + visible: None, + cell_edit: None, + viewport: None, + }, + }; + broadcast(vec![user_1.session_id], file_id, state, message) + .await + .unwrap(); + + // TODO(ddimaria): mock the splitsink sender to test the actual sending + } + + #[tokio::test] + async fn test_change_cell_edit() { + let (state, file_id, user_1) = setup().await; + let message = MessageResponse::UserUpdate { + session_id: user_1.session_id, + file_id, + update: UserStateUpdate { + selection: None, + sheet_id: None, + x: None, + y: None, + visible: None, + cell_edit: Some(CellEdit { + text: "test".to_string(), + cursor: 0, + active: true, + code_editor: false, + bold: None, + italic: None, + }), + viewport: None, + }, + }; + broadcast(vec![user_1.session_id], file_id, state, message) + .await + .unwrap(); + + // TODO(ddimaria): mock the splitsink sender to test the actual sending + } + + #[tokio::test] + async fn test_change_viewport() { + let (state, file_id, user_1) = setup().await; + let message = MessageResponse::UserUpdate { + session_id: user_1.session_id, + file_id, + update: UserStateUpdate { + selection: None, + sheet_id: None, + x: None, + y: None, + visible: None, + cell_edit: None, + viewport: Some("viewport".to_string()), + }, + }; + broadcast(vec![user_1.session_id], file_id, state, message) + .await + .unwrap(); + + // TODO(ddimaria): mock the splitsink sender to test the actual sending + } + + #[tokio::test] + async fn test_transaction() { + let (state, file_id, user_1) = setup().await; + let id = Uuid::new_v4(); + let message = MessageResponse::Transaction { + id, + file_id, + operations: "test".to_string(), + sequence_num: 1, + }; + broadcast(vec![user_1.session_id], file_id, state, message) + .await + .unwrap(); + + // TODO(ddimaria): mock the splitsink sender to test the actual sending + } +} diff --git a/quadratic-multiplayer/src/message/mod.rs b/quadratic-multiplayer/src/message/mod.rs new file mode 100644 index 0000000000..f775e1bc05 --- /dev/null +++ b/quadratic-multiplayer/src/message/mod.rs @@ -0,0 +1,49 @@ +use axum::extract::ws::Message; +use futures_util::SinkExt; +use std::sync::Arc; +use tokio::task::JoinHandle; +use uuid::Uuid; + +use crate::message::response::MessageResponse; +use crate::state::State; + +pub mod handle; +pub mod request; +pub mod response; + +/// Broadcast a message to all users in a room except the sender. +/// All messages are sent in a separate thread. +#[tracing::instrument(level = "trace")] +pub(crate) fn broadcast( + exclude: Vec, + file_id: Uuid, + state: Arc, + message: MessageResponse, +) -> JoinHandle<()> { + // println!("message: {:?}", message); + tokio::spawn(async move { + let result = async { + for (_, user) in state + .get_room(&file_id) + .await? + .users + .iter() + .filter(|(_, user)| !exclude.contains(&user.session_id)) + { + if let Some(sender) = &user.socket { + sender + .lock() + .await + .send(Message::Text(serde_json::to_string(&message)?)) + .await?; + } + } + + Ok::<_, anyhow::Error>(()) + }; + + if let Err(e) = result.await { + tracing::warn!("Error broadcasting message: {:?}", e.to_string()); + } + }) +} diff --git a/quadratic-multiplayer/src/message/request.rs b/quadratic-multiplayer/src/message/request.rs new file mode 100644 index 0000000000..691764e369 --- /dev/null +++ b/quadratic-multiplayer/src/message/request.rs @@ -0,0 +1,53 @@ +//! Websocket Message Requests +//! +//! A central place for storing websocket messages requests. + +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::state::user::{CellEdit, UserStateUpdate}; + +// NOTE: needs to be kept in sync with multiplayerTypes.ts +#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[serde(tag = "type")] +pub(crate) enum MessageRequest { + EnterRoom { + session_id: Uuid, + user_id: String, + file_id: Uuid, + first_name: String, + last_name: String, + email: String, + image: String, + sheet_id: Uuid, + selection: String, + cell_edit: CellEdit, + viewport: String, + }, + LeaveRoom { + session_id: Uuid, + file_id: Uuid, + }, + UserUpdate { + session_id: Uuid, + file_id: Uuid, + update: UserStateUpdate, + }, + Transaction { + id: Uuid, + session_id: Uuid, + file_id: Uuid, + + // todo: this is a stringified Vec. Eventually, Operation should be a shared type. + operations: String, + }, + GetTransactions { + file_id: Uuid, + session_id: Uuid, + min_sequence_num: u64, + }, + Heartbeat { + session_id: Uuid, + file_id: Uuid, + }, +} diff --git a/quadratic-multiplayer/src/message/response.rs b/quadratic-multiplayer/src/message/response.rs new file mode 100644 index 0000000000..3c76e2bd3b --- /dev/null +++ b/quadratic-multiplayer/src/message/response.rs @@ -0,0 +1,45 @@ +//! Websocket Message Responses +//! +//! A central place for storing websocket messages responses. + +use serde::Serialize; +use uuid::Uuid; + +use crate::state::transaction_queue::Transaction; +use crate::state::user::UserStateUpdate; +use crate::state::{room::Room, user::User}; + +// NOTE: needs to be kept in sync with multiplayerTypes.ts +#[derive(Serialize, Debug, Clone, PartialEq)] +#[serde(tag = "type")] +pub(crate) enum MessageResponse { + UsersInRoom { + users: Vec, + }, + UserUpdate { + session_id: Uuid, + file_id: Uuid, + update: UserStateUpdate, + }, + Transaction { + id: Uuid, + file_id: Uuid, + // todo: this is a stringified Vec. Eventually, Operation should be a shared type. + operations: String, + sequence_num: u64, + }, + Transactions { + transactions: Vec, + }, + CurrentTransaction { + sequence_num: u64, + }, +} + +impl From for MessageResponse { + fn from(room: Room) -> Self { + MessageResponse::UsersInRoom { + users: room.users.into_iter().map(|user| (user.1)).collect(), + } + } +} diff --git a/quadratic-multiplayer/src/server.rs b/quadratic-multiplayer/src/server.rs index 28cb1aac03..613953b375 100644 --- a/quadratic-multiplayer/src/server.rs +++ b/quadratic-multiplayer/src/server.rs @@ -3,12 +3,13 @@ //! Handle bootstrapping and starting the websocket server. Adds global state //! to be shared across all requests and threads. Adds tracing/logging. -use anyhow::Result; +use anyhow::{anyhow, Result}; use axum::{ extract::{ connect_info::ConnectInfo, ws::{Message, WebSocket, WebSocketUpgrade}, }, + http::StatusCode, response::IntoResponse, routing::get, Extension, Router, @@ -22,11 +23,16 @@ use std::{net::SocketAddr, sync::Arc}; use tokio::sync::Mutex; use tower_http::trace::{DefaultMakeSpan, TraceLayer}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; +use uuid::Uuid; use crate::{ + auth::{authorize, get_jwks}, + background_worker, config::{config, Config}, - message::{handle_message, MessageRequest, MessageResponse}, - state::State, + message::{ + broadcast, handle::handle_message, request::MessageRequest, response::MessageResponse, + }, + state::{Settings, State}, }; /// Construct the application router. This is separated out so that it can be @@ -45,8 +51,16 @@ pub(crate) fn app(state: Arc) -> Router { } /// Start the websocket server. This is the entrypoint for the application. +#[tracing::instrument(level = "trace")] pub(crate) async fn serve() -> Result<()> { - let Config { host, port } = config()?; + let Config { + host, + port, + auth0_jwks_uri, + heartbeat_check_s, + heartbeat_timeout_s, + authenticate_jwt, + } = config()?; tracing_subscriber::registry() .with( @@ -56,12 +70,23 @@ pub(crate) async fn serve() -> Result<()> { .with(tracing_subscriber::fmt::layer()) .init(); - let state = Arc::new(State::new()); - let app = app(state); + let jwks = get_jwks(&auth0_jwks_uri).await?; + let settings = Settings { + jwks: Some(jwks), + authenticate_jwt, + }; + let state = Arc::new(State::new().with_settings(settings)); + let app = app(Arc::clone(&state)); let listener = tokio::net::TcpListener::bind(format!("{host}:{port}")).await?; tracing::info!("listening on {}", listener.local_addr()?); + if !authenticate_jwt { + tracing::warn!("JWT authentication is disabled"); + } + + background_worker::start(Arc::clone(&state), heartbeat_check_s, heartbeat_timeout_s).await; + axum::serve( listener, app.into_make_service_with_connect_info::(), @@ -72,58 +97,106 @@ pub(crate) async fn serve() -> Result<()> { } // Handle the websocket upgrade from http. +#[tracing::instrument(level = "trace")] async fn ws_handler( ws: WebSocketUpgrade, user_agent: Option>, addr: Option>, Extension(state): Extension>, + cookie: Option>, ) -> impl IntoResponse { let user_agent = user_agent.map_or("Unknown user agent".into(), |user_agent| { user_agent.to_string() }); let addr = addr.map_or("Unknown address".into(), |addr| addr.to_string()); + let connection_id = Uuid::new_v4(); - tracing::info!("`{user_agent}` at {addr} connected."); + tracing::info!("`{user_agent}` at {addr} connected: connection_id={connection_id}"); + + if state.settings.authenticate_jwt { + // validate the JWT + let result = async { + let cookie = cookie.ok_or_else(|| anyhow!("No cookie found"))?; + let token = cookie.get("jwt").ok_or_else(|| anyhow!("No JWT found"))?; + let jwks: jsonwebtoken::jwk::JwkSet = state + .settings + .jwks + .clone() + .ok_or_else(|| anyhow!("No JWKS found"))?; + + authorize(&jwks, token, false, true)?; + + Ok::<_, anyhow::Error>(()) + } + .await; + + if let Err(error) = result { + tracing::warn!("Error authorizing user: {:?}", error); + return (StatusCode::BAD_REQUEST, "Invalid token").into_response(); + } + } // upgrade the connection - ws.on_upgrade(move |socket| handle_socket(socket, state, addr)) + ws.on_upgrade(move |socket| handle_socket(socket, state, addr, connection_id)) } // After websocket is established, delegate incoming messages as they arrive. -async fn handle_socket(socket: WebSocket, state: Arc, addr: String) { +#[tracing::instrument(level = "trace")] +async fn handle_socket(socket: WebSocket, state: Arc, addr: String, connection_id: Uuid) { let (sender, mut receiver) = socket.split(); let sender = Arc::new(Mutex::new(sender)); while let Some(Ok(msg)) = receiver.next().await { - let response = process_message(msg, Arc::clone(&sender), Arc::clone(&state)).await; + let response = + process_message(msg, Arc::clone(&sender), Arc::clone(&state), connection_id).await; match response { Ok(ControlFlow::Continue(_)) => {} Ok(ControlFlow::Break(_)) => break, Err(e) => { - tracing::error!("Error processing message: {:?}", e); + tracing::warn!("Error processing message: {:?}", e); + } + } + } + + // websocket is closed, remove the user from any rooms they were in and broadcast + if let Ok(rooms) = state.clear_connections(connection_id).await { + tracing::info!("Removing stale users from rooms: {:?}", rooms); + + for file_id in rooms.into_iter() { + // only broadcast if the room still exists + if let Ok(room) = state.get_room(&file_id).await { + tracing::info!("Broadcasting room {file_id} after removing stale users"); + + let message = MessageResponse::from(room.to_owned()); + broadcast(vec![], file_id, Arc::clone(&state), message); } } } // returning from the handler closes the websocket connection - tracing::info!("Websocket context {addr} destroyed"); + tracing::info!("Websocket context {addr} destroyed: connection_id={connection_id}"); } /// Based on the incoming message type, perform some action and return a response. +#[tracing::instrument(level = "trace")] async fn process_message( msg: Message, sender: Arc>>, state: Arc, + connection_id: Uuid, ) -> Result, ()>> { match msg { Message::Text(text) => { let messsage_request = serde_json::from_str::(&text)?; let message_response = - handle_message(messsage_request, state, Arc::clone(&sender)).await?; - let response = Message::Text(serde_json::to_string(&message_response)?); + handle_message(messsage_request, state, Arc::clone(&sender), connection_id).await?; + + if let Some(message_response) = message_response { + let response = Message::Text(serde_json::to_string(&message_response)?); - (*sender.lock().await).send(response).await?; + (*sender.lock().await).send(response).await?; + } } Message::Binary(d) => { tracing::info!( @@ -152,109 +225,195 @@ async fn process_message( pub(crate) mod tests { use super::*; - use crate::{ - state::Room, - test_util::{integration_test, new_user}, - }; + use crate::state::user::{CellEdit, User, UserStateUpdate}; + use crate::test_util::{integration_test_send_and_receive, integration_test_setup, new_user}; + use quadratic_core::controller::operations::operation::Operation; + use tokio::net::TcpStream; + use tokio_tungstenite::{MaybeTlsStream, WebSocketStream}; use uuid::Uuid; - #[tokio::test] - async fn user_enters_a_room() { - let state = Arc::new(State::new()); - let file_id = Uuid::new_v4(); + async fn add_user_via_ws( + file_id: Uuid, + socket: Arc>>>, + ) -> User { let user = new_user(); - let user_id = user.id.clone(); + let session_id = user.session_id; let request = MessageRequest::EnterRoom { - user_id: user_id.clone(), + session_id, + user_id: user.user_id.clone(), file_id, + sheet_id: user.state.sheet_id, + selection: String::new(), first_name: user.first_name.clone(), last_name: user.last_name.clone(), + email: user.email.clone(), image: user.image.clone(), + cell_edit: CellEdit::default(), + viewport: "initial viewport".to_string(), }; - let expected = MessageResponse::Room { - room: Room { - file_id, - users: vec![(user_id, user)].into_iter().collect(), - }, - }; - let response = integration_test(state, request).await; - assert_eq!(response, serde_json::to_string(&expected).unwrap()); + integration_test_send_and_receive(socket, request, true).await; + + user } - #[tokio::test] - async fn user_moves_a_mouse() { + async fn setup() -> ( + Arc>>>, + Arc, + Uuid, + Uuid, + User, + ) { let state = Arc::new(State::new()); - let user = new_user(); - let user_id = user.id.clone(); + let connection_id = Uuid::new_v4(); let file_id = Uuid::new_v4(); - let x = 0 as f64; - let y = 0 as f64; - let request = MessageRequest::MouseMove { - user_id: user_id.clone(), + let socket = integration_test_setup(state.clone()).await; + let socket = Arc::new(Mutex::new(socket)); + let user = add_user_via_ws(file_id, socket.clone()).await; + + (socket.clone(), state, connection_id, file_id, user) + } + + async fn assert_user_changes_state(update: UserStateUpdate) { + let (socket, _, _, file_id, _) = setup().await; + let new_user = new_user(); + let session_id = new_user.session_id; + let request = MessageRequest::UserUpdate { + session_id, file_id, - x: Some(x), - y: Some(y), + update: update.clone(), }; - let expected = MessageResponse::MouseMove { - user_id: user_id.clone(), + let expected = MessageResponse::UserUpdate { + session_id, file_id, - x: Some(x), - y: Some(y), + update, }; - state.enter_room(file_id, &user).await; - - let response = integration_test(state.clone(), request).await; + let response = integration_test_send_and_receive(socket, request, true).await; - assert_eq!(response, serde_json::to_string(&expected).unwrap()); + assert_eq!(response, Some(serde_json::to_string(&expected).unwrap())); } #[tokio::test] - async fn user_changes_selection() { - let state = Arc::new(State::new()); - let user = new_user(); - let user_id = user.id.clone(); - let file_id = Uuid::new_v4(); - let request = MessageRequest::ChangeSelection { - user_id: user_id.clone(), + async fn user_enters_a_room() { + let (socket, _, _, file_id, user) = setup().await; + let new_user = new_user(); + let session_id = new_user.session_id; + let request = MessageRequest::EnterRoom { + session_id, + user_id: new_user.user_id.clone(), file_id, - selection: "test".to_string(), + sheet_id: new_user.state.sheet_id, + selection: String::new(), + first_name: new_user.first_name.clone(), + last_name: new_user.last_name.clone(), + email: new_user.email.clone(), + image: new_user.image.clone(), + cell_edit: CellEdit::default(), + viewport: "initial viewport".to_string(), + }; + let expected_1 = MessageResponse::UsersInRoom { + users: vec![new_user.clone(), user.clone()], }; - let expected = MessageResponse::ChangeSelection { - user_id: user_id.clone(), + let expected_2 = MessageResponse::UsersInRoom { + users: vec![user, new_user], + }; + let response = integration_test_send_and_receive(socket, request, true).await; + + // order is brittle, this feels hacky + assert!( + response == Some(serde_json::to_string(&expected_1).unwrap()) + || response == Some(serde_json::to_string(&expected_2).unwrap()) + ); + } + + #[tokio::test] + async fn user_leaves_a_room() { + let (socket, state, connection_id, file_id, user) = setup().await; + let new_user = new_user(); + let session_id = new_user.session_id; + let request = MessageRequest::LeaveRoom { + session_id, file_id, - selection: "test".to_string(), + }; + let expected = MessageResponse::UsersInRoom { + users: vec![user.clone()], + }; + + state.enter_room(file_id, &new_user, connection_id).await; + + let response = integration_test_send_and_receive(socket, request, true).await; + + assert_eq!(response, Some(serde_json::to_string(&expected).unwrap())); + } + + #[tokio::test] + async fn user_moves_a_mouse() { + let update = UserStateUpdate { + x: Some(1.0), + y: Some(2.0), + selection: None, + sheet_id: None, + visible: None, + cell_edit: None, + viewport: None, }; - state.enter_room(file_id, &user).await; + assert_user_changes_state(update).await; + } - let response = integration_test(state.clone(), request).await; + #[tokio::test] + async fn user_changes_selection() { + let update = UserStateUpdate { + selection: Some("test".to_string()), + sheet_id: None, + x: None, + y: None, + visible: None, + cell_edit: None, + viewport: None, + }; - assert_eq!(response, serde_json::to_string(&expected).unwrap()); + assert_user_changes_state(update).await; + } + + #[tokio::test] + async fn user_changes_viewport() { + let update = UserStateUpdate { + selection: None, + sheet_id: None, + x: None, + y: None, + visible: None, + cell_edit: None, + viewport: Some("new_viewport".to_string()), + }; + + assert_user_changes_state(update).await; } #[tokio::test] async fn user_shares_operations() { - let state = Arc::new(State::new()); - let user = new_user(); - let user_id = user.id.clone(); - let file_id = Uuid::new_v4(); + let (socket, _, _, file_id, _) = setup().await; + let new_user = new_user(); + let session_id = new_user.session_id; + let operations = serde_json::to_string::>(&vec![]).unwrap(); + let id = Uuid::new_v4(); let request = MessageRequest::Transaction { - user_id: user_id.clone(), + id, + session_id, file_id, - operations: "test".to_string(), + operations: operations.clone(), }; let expected = MessageResponse::Transaction { - user_id: user_id.clone(), + id, file_id, - operations: "test".to_string(), + operations: operations.clone(), + sequence_num: 1, }; - state.enter_room(file_id, &user).await; - - let response = integration_test(state.clone(), request).await; + let response = integration_test_send_and_receive(socket, request, true).await; - assert_eq!(response, serde_json::to_string(&expected).unwrap()); + assert_eq!(response, Some(serde_json::to_string(&expected).unwrap())); } } diff --git a/quadratic-multiplayer/src/state.rs b/quadratic-multiplayer/src/state.rs deleted file mode 100644 index 6c5c7914cb..0000000000 --- a/quadratic-multiplayer/src/state.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Shared State -//! -//! Store information about the state of the application in a send + sync -//! struct. All access and mutations to state should be performed here. - -use std::{collections::HashMap, sync::Arc}; - -use anyhow::{anyhow, Result}; -use axum::extract::ws::{Message, WebSocket}; -use futures_util::stream::SplitSink; -use serde::Serialize; -use tokio::sync::Mutex; -use uuid::Uuid; - -#[derive(Serialize, Debug, Clone)] -pub(crate) struct User { - #[serde(skip_serializing)] - pub(crate) id: String, - pub(crate) first_name: String, - pub(crate) last_name: String, - pub(crate) image: String, - #[serde(skip_serializing)] - pub(crate) socket: Option>>>, -} - -impl PartialEq for User { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - && self.first_name == other.first_name - && self.last_name == other.last_name - && self.image == other.image - } -} - -#[derive(Serialize, Debug, Clone, PartialEq)] -pub(crate) struct Room { - pub(crate) file_id: Uuid, - pub(crate) users: HashMap, -} - -impl Room { - pub(crate) fn new(file_id: Uuid) -> Self { - Room { - file_id, - users: HashMap::new(), - } - } -} - -#[derive(Debug)] -pub(crate) struct State { - pub(crate) rooms: Mutex>, -} - -impl State { - pub(crate) fn new() -> Self { - State { - rooms: Mutex::new(HashMap::new()), - } - } - - /// Retrieves a copy of a room. - pub(crate) async fn get_room(&self, file_id: &Uuid) -> Result { - let rooms = self.rooms.lock().await; - let room = rooms - .get(file_id) - .ok_or(anyhow!("Room {file_id} not found"))? - .to_owned(); - - Ok(room) - } - - /// Add a user to a room. If the room doesn't exist, it is created. Users - /// are only added to a room once (HashMap). - pub(crate) async fn enter_room(&self, file_id: Uuid, user: &User) -> bool { - let mut rooms = self.rooms.lock().await; - let room = rooms.entry(file_id).or_insert_with(|| Room::new(file_id)); - - let user_id = user.id.clone(); - - tracing::trace!("User {:?} entered room {:?}", user, room); - - room.users.insert(user_id, user.clone()).is_none() - } -} - -#[cfg(test)] -mod tests { - use crate::test_util::new_user; - - use super::*; - - #[tokio::test] - async fn enters_and_retrieves_a_room() { - let state = State::new(); - let file_id = Uuid::new_v4(); - let user = new_user(); - - let is_new = state.enter_room(file_id, &user).await; - let room = state.get_room(&file_id).await.unwrap(); - let user = room.users.get(&user.id).unwrap(); - - assert!(is_new); - assert_eq!(state.rooms.lock().await.len(), 1); - assert_eq!(room.users.len(), 1); - assert_eq!(room.users.get(&user.id), Some(user)); - } -} diff --git a/quadratic-multiplayer/src/state/connection.rs b/quadratic-multiplayer/src/state/connection.rs new file mode 100644 index 0000000000..49fc855402 --- /dev/null +++ b/quadratic-multiplayer/src/state/connection.rs @@ -0,0 +1,83 @@ +use anyhow::{anyhow, Result}; +use uuid::Uuid; + +use crate::state::State; + +impl State { + /// Retrieve the session_id from connections + pub(crate) async fn get_session_id(&self, connection_id: Uuid) -> Result { + let session_id = self + .connections + .lock() + .await + .get(&connection_id) + .ok_or(anyhow!( + "connection_id {} not found in sockets", + connection_id + ))? + .to_owned(); + + Ok(session_id) + } + + /// Removes a connection from the state. If the connection is in a room, leave the room. + #[tracing::instrument(level = "trace")] + pub(crate) async fn clear_connections(&self, connection_id: Uuid) -> Result> { + let mut affected_rooms = vec![]; + let rooms = self.rooms.lock().await.clone(); + + for (file_id, room) in rooms.iter() { + let session_id = self.get_session_id(connection_id).await?; + if let Some(user) = room.users.get(&session_id) { + tracing::info!("Removing connection_id {connection_id} from room {file_id}"); + + self.leave_room(room.file_id, &user.session_id).await?; + affected_rooms.push(file_id.to_owned()); + } + } + + tracing::info!("Removing connection_id {}", connection_id); + + self.connections.lock().await.remove(&connection_id); + Ok(affected_rooms) + } +} + +#[cfg(test)] +mod tests { + use crate::test_util::assert_anyhow_error; + + use super::*; + + async fn setup() -> (State, Uuid, Uuid) { + let state = State::new(); + let session_id = Uuid::new_v4(); + let connection_id = Uuid::new_v4(); + + state + .connections + .lock() + .await + .insert(connection_id, session_id); + + (state, session_id, connection_id) + } + + #[tokio::test] + async fn get_session_id() { + let (state, session_id, connection_id) = setup().await; + let result = state.get_session_id(connection_id).await.unwrap(); + + assert_eq!(result, session_id); + } + + #[tokio::test] + async fn clear_connections() { + let (state, _, connection_id) = setup().await; + state.clear_connections(connection_id).await.unwrap(); + let result = state.get_session_id(connection_id).await; + let expected = format!("connection_id {connection_id} not found in sockets"); + + assert_anyhow_error(result, &expected); + } +} diff --git a/quadratic-multiplayer/src/state/mod.rs b/quadratic-multiplayer/src/state/mod.rs new file mode 100644 index 0000000000..8913136b31 --- /dev/null +++ b/quadratic-multiplayer/src/state/mod.rs @@ -0,0 +1,49 @@ +//! Shared State +//! +//! Store information about the state of the application in a send + sync +//! struct. All access and mutations to state should be performed here. + +pub mod connection; +pub mod room; +pub mod transaction_queue; +pub mod user; + +use jsonwebtoken::jwk::JwkSet; +use std::collections::HashMap; +use tokio::sync::Mutex; +use uuid::Uuid; + +use crate::state::room::Room; + +use self::transaction_queue::TransactionQueue; + +#[derive(Debug)] +pub(crate) struct State { + pub(crate) rooms: Mutex>, + pub(crate) connections: Mutex>, + pub(crate) transaction_queue: Mutex, + pub(crate) settings: Settings, +} + +#[derive(Debug, Default)] +pub(crate) struct Settings { + pub(crate) jwks: Option, + pub(crate) authenticate_jwt: bool, +} + +impl State { + pub(crate) fn new() -> Self { + // TODO(ddimaria): seed transaction_queue with the sequence_num from the database for each file + State { + rooms: Mutex::new(HashMap::new()), + connections: Mutex::new(HashMap::new()), + transaction_queue: Mutex::new(TransactionQueue::new()), + settings: Settings::default(), + } + } + + pub(crate) fn with_settings(mut self, settings: Settings) -> Self { + self.settings = settings; + self + } +} diff --git a/quadratic-multiplayer/src/state/room.rs b/quadratic-multiplayer/src/state/room.rs new file mode 100644 index 0000000000..d3906cff6d --- /dev/null +++ b/quadratic-multiplayer/src/state/room.rs @@ -0,0 +1,157 @@ +use anyhow::{anyhow, Result}; +use quadratic_core::controller::GridController; +use serde::Serialize; +use std::collections::HashMap; +use uuid::Uuid; + +use crate::state::{user::User, State}; +use crate::{get_mut_room, get_or_create_room, get_room}; + +#[derive(Serialize, Debug, Clone, PartialEq)] +pub(crate) struct Room { + pub(crate) file_id: Uuid, + pub(crate) users: HashMap, + #[serde(skip_serializing)] + pub(crate) grid: GridController, +} + +impl Room { + pub(crate) fn new(file_id: Uuid) -> Self { + Room { + file_id, + users: HashMap::new(), + grid: GridController::new(), + // TODO(ddimaria): load the grid from the file + // grid: GridController::from_grid(load_file(file).unwrap()), + } + } +} + +impl State { + /// Retrieves a copy of a room. + pub(crate) async fn get_room(&self, file_id: &Uuid) -> Result { + let room = get_room!(self, file_id)?.to_owned(); + + Ok(room) + } + + /// Add a user to a room. If the room doesn't exist, it is created. Users + /// are only added to a room once (HashMap). Returns true if the user was + /// newly added. + #[tracing::instrument(level = "trace")] + pub(crate) async fn enter_room(&self, file_id: Uuid, user: &User, connection_id: Uuid) -> bool { + let is_new = get_or_create_room!(self, file_id) + .users + .insert(user.session_id.to_owned(), user.to_owned()) + .is_none(); + + self.connections + .lock() + .await + .insert(connection_id, user.session_id); + + tracing::info!("User {:?} entered room {:?}", user.session_id, file_id); + + is_new + } + + /// Removes a user from a room. If the room is empty, it deletes the room. + /// Returns true if the room still exists after the user leaves. + #[tracing::instrument(level = "trace")] + pub(crate) async fn leave_room(&self, file_id: Uuid, session_id: &Uuid) -> Result { + get_mut_room!(self, file_id)?.users.remove(session_id); + let num_in_room = get_room!(self, file_id)?.users.len(); + + tracing::info!( + "User {:?} is leaving room {}, {} user(s) left", + session_id, + file_id, + num_in_room + ); + + if num_in_room == 0 { + self.remove_room(file_id).await; + } + + Ok(num_in_room != 0) + } + + /// Removes a room. + pub(crate) async fn remove_room(&self, file_id: Uuid) { + self.rooms.lock().await.remove(&file_id); + + tracing::info!("Room {file_id} removed"); + } +} + +#[macro_export] +macro_rules! get_room { + ( $self:ident, $file_id:ident ) => { + $self + .rooms + .lock() + .await + .get(&$file_id) + .ok_or(anyhow!("Room {} not found", $file_id)) + }; +} + +#[macro_export] +macro_rules! get_mut_room { + ( $self:ident, $file_id:ident ) => { + $self + .rooms + .lock() + .await + .get_mut(&$file_id) + .ok_or(anyhow!("Room {} not found", $file_id)) + }; +} + +#[macro_export] +macro_rules! get_or_create_room { + ( $self:ident, $file_id:ident ) => { + $self.rooms.lock().await.entry($file_id).or_insert_with(|| { + tracing::info!("Room {} created", $file_id); + Room::new($file_id) + }) + }; +} + +#[cfg(test)] +mod tests { + use crate::test_util::new_user; + + use super::*; + + #[tokio::test] + async fn enters_retrieves_leaves_and_removes_a_room() { + let state = State::new(); + let connection_id = Uuid::new_v4(); + let file_id = Uuid::new_v4(); + let user = new_user(); + let user2 = new_user(); + + let is_new = state.enter_room(file_id, &user, connection_id).await; + let room = state.get_room(&file_id).await.unwrap(); + let user = room.users.get(&user.session_id).unwrap(); + + assert!(is_new); + assert_eq!(state.rooms.lock().await.len(), 1); + assert_eq!(room.users.len(), 1); + assert_eq!(room.users.get(&user.session_id), Some(user)); + + // leave the room of 2 users + state.enter_room(file_id, &user2, connection_id).await; + state.leave_room(file_id, &user.session_id).await.unwrap(); + let room = state.get_room(&file_id).await.unwrap(); + + assert_eq!(room.users.len(), 1); + assert_eq!(room.users.get(&user2.session_id), Some(&user2)); + + // leave a room of 1 user + state.leave_room(file_id, &user2.session_id).await.unwrap(); + let room = state.get_room(&file_id).await; + assert!(room.is_err()); + } +} diff --git a/quadratic-multiplayer/src/state/transaction_queue.rs b/quadratic-multiplayer/src/state/transaction_queue.rs new file mode 100644 index 0000000000..5750765712 --- /dev/null +++ b/quadratic-multiplayer/src/state/transaction_queue.rs @@ -0,0 +1,141 @@ +use anyhow::{anyhow, Result}; +use quadratic_core::controller::operations::operation::Operation; +use serde::Serialize; +use std::collections::HashMap; +use uuid::Uuid; + +#[derive(Serialize, Debug, PartialEq, Clone)] +pub(crate) struct Transaction { + pub(crate) id: Uuid, + pub(crate) file_id: Uuid, + pub(crate) operations: Vec, + pub(crate) sequence_num: u64, +} + +impl Transaction { + pub(crate) fn new( + id: Uuid, + file_id: Uuid, + operations: Vec, + sequence_num: u64, + ) -> Self { + Transaction { + id, + file_id, + operations, + sequence_num, + } + } +} + +#[derive(Debug, Default)] +pub(crate) struct TransactionQueue { + pub(crate) queue: HashMap)>, +} + +impl TransactionQueue { + pub(crate) fn new() -> Self { + Default::default() + } + + pub(crate) fn push(&mut self, id: Uuid, file_id: Uuid, operations: Vec) -> u64 { + let (sequence_num, transactions) = self.queue.entry(file_id).or_insert_with(|| (0, vec![])); + + *sequence_num += 1; + + let transaction = Transaction::new(id, file_id, operations, *sequence_num); + transactions.push(transaction); + + sequence_num.to_owned() + } + + pub(crate) fn get_transactions(&mut self, file_id: Uuid) -> Result> { + let transactions = self + .queue + .get(&file_id) + .ok_or_else(|| anyhow!("file_id {file_id} not found in transaction queue"))? + .1 + .to_owned(); + + Ok(transactions) + } + + pub(crate) fn get_transactions_min_sequence_num( + &mut self, + file_id: Uuid, + min_sequence_num: u64, + ) -> Result> { + let transactions = self + .get_transactions(file_id)? + .into_iter() + .filter(|transaction| transaction.sequence_num >= min_sequence_num) + .collect(); + + Ok(transactions) + } + + pub(crate) fn get_sequence_num(&mut self, file_id: Uuid) -> Result { + let sequence_num = self + .queue + .get(&file_id) + .ok_or_else(|| anyhow!("file_id {file_id} not found in transaction queue"))? + .0; + + Ok(sequence_num) + } +} +#[cfg(test)] +mod tests { + use crate::{ + state::State, + test_util::{grid_setup, operation}, + }; + + fn setup() -> (State, Uuid) { + let state = State::new(); + let file_id = Uuid::new_v4(); + + (state, file_id) + } + + use super::*; + #[tokio::test] + async fn transaction_queue() { + let (state, file_id) = setup(); + let mut grid = grid_setup(); + let transaction_id_1 = Uuid::new_v4(); + let operations_1 = operation(&mut grid, 0, 0, "1"); + let transaction_id_2 = Uuid::new_v4(); + let operations_2 = operation(&mut grid, 1, 0, "2"); + + state.transaction_queue.lock().await.push( + transaction_id_1, + file_id, + vec![operations_1.clone()], + ); + + let mut transaction_queue = state.transaction_queue.lock().await; + let transactions = transaction_queue.get_transactions(file_id).unwrap(); + assert_eq!(transactions.len(), 1); + assert_eq!(transaction_queue.get_sequence_num(file_id).unwrap(), 1); + assert_eq!(transactions[0].operations, vec![operations_1.clone()]); + assert_eq!(transactions[0].sequence_num, 1); + + std::mem::drop(transaction_queue); + + state.transaction_queue.lock().await.push( + transaction_id_2, + file_id, + vec![operations_2.clone()], + ); + + let mut transaction_queue = state.transaction_queue.lock().await; + let transactions = transaction_queue.get_transactions(file_id).unwrap(); + assert_eq!(transactions.len(), 2); + assert_eq!(transaction_queue.get_sequence_num(file_id).unwrap(), 2); + assert_eq!(transactions[0].operations, vec![operations_1.clone()]); + assert_eq!(transactions[0].sequence_num, 1); + assert_eq!(transactions[1].operations, vec![operations_2.clone()]); + assert_eq!(transactions[1].sequence_num, 2); + } +} diff --git a/quadratic-multiplayer/src/state/user.rs b/quadratic-multiplayer/src/state/user.rs new file mode 100644 index 0000000000..98a44b5f38 --- /dev/null +++ b/quadratic-multiplayer/src/state/user.rs @@ -0,0 +1,235 @@ +use anyhow::{anyhow, Result}; +use axum::extract::ws::{Message, WebSocket}; +use chrono::{DateTime, Utc}; +use futures_util::stream::SplitSink; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use tokio::sync::Mutex; +use uuid::Uuid; + +use crate::state::State; +use crate::{get_mut_room, get_room}; + +#[derive(Serialize, Debug, Clone)] +pub(crate) struct User { + pub session_id: Uuid, + pub user_id: String, + pub first_name: String, + pub last_name: String, + pub email: String, + pub image: String, + #[serde(flatten)] + pub state: UserState, + #[serde(skip_serializing)] + pub socket: Option>>>, + #[serde(skip_serializing)] + pub last_heartbeat: DateTime, +} + +impl PartialEq for User { + fn eq(&self, other: &Self) -> bool { + self.session_id == other.session_id + && self.user_id == other.user_id + && self.first_name == other.first_name + && self.last_name == other.last_name + && self.image == other.image + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)] +pub(crate) struct CellEdit { + pub active: bool, + pub text: String, + pub cursor: u32, + pub code_editor: bool, + pub bold: Option, + pub italic: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub(crate) struct UserState { + pub sheet_id: Uuid, + pub selection: String, + pub cell_edit: CellEdit, + pub x: f64, + pub y: f64, + pub visible: bool, + pub viewport: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub(crate) struct UserStateUpdate { + pub sheet_id: Option, + pub selection: Option, + pub cell_edit: Option, + pub x: Option, + pub y: Option, + pub visible: Option, + pub viewport: Option, +} + +impl State { + /// Retrieves a copy of a user in a room + pub(crate) async fn _get_user_in_room( + &self, + file_id: &Uuid, + session_id: &Uuid, + ) -> Result { + let user = get_room!(self, file_id)? + .users + .get(session_id) + .ok_or(anyhow!("User {} not found in Room {}", session_id, file_id))? + .to_owned(); + + Ok(user) + } + + /// Remove stale users in a room. Returns the number of users removed in the room, and the number left. + #[tracing::instrument(level = "trace")] + pub(crate) async fn remove_stale_users_in_room( + &self, + file_id: Uuid, + heartbeat_timeout_s: i64, + ) -> Result<(usize, usize)> { + let mut active_users = 0; + let stale_users = get_room!(self, file_id)? + .users + .iter() + .filter(|(_, user)| { + let no_heartbeat = + user.last_heartbeat.timestamp() + heartbeat_timeout_s < Utc::now().timestamp(); + + if !no_heartbeat { + active_users += 1; + } + + no_heartbeat + }) + .map(|(user_id, _)| user_id.to_owned()) + .collect::>(); + + for user_id in stale_users.iter() { + tracing::info!("Removing stale user {} from room {}", user_id, file_id); + + self.leave_room(file_id, user_id).await?; + } + + Ok((stale_users.len(), active_users)) + } + + /// Updates a user's heartbeat in a room + #[tracing::instrument(level = "trace")] + pub(crate) async fn update_user_heartbeat( + &self, + file_id: Uuid, + session_id: &Uuid, + ) -> Result<()> { + get_mut_room!(self, file_id)? + .users + .entry(session_id.to_owned()) + .and_modify(|user| { + user.last_heartbeat = Utc::now(); + tracing::trace!("Updating heartbeat for {session_id}"); + }); + + Ok(()) + } + + /// updates a user's state in a room + pub(crate) async fn update_user_state( + &self, + file_id: &Uuid, + session_id: &Uuid, + user_state: &UserStateUpdate, + ) -> Result<()> { + get_mut_room!(self, file_id)? + .users + .entry(session_id.to_owned()) + .and_modify(|user| { + if let Some(sheet_id) = user_state.sheet_id { + user.state.sheet_id = sheet_id; + } + if let Some(selection) = &user_state.selection { + user.state.selection = selection.to_owned(); + } + if let Some(x) = user_state.x { + user.state.x = x; + } + if let Some(y) = user_state.y { + user.state.y = y; + } + if let Some(visible) = user_state.visible { + user.state.visible = visible; + } + if let Some(cell_edit) = user_state.cell_edit.to_owned() { + user.state.cell_edit = cell_edit; + } + if let Some(viewport) = user_state.viewport.to_owned() { + user.state.viewport = viewport; + } + + user.last_heartbeat = Utc::now(); + }); + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::test_util::{assert_anyhow_error, new_user}; + + async fn setup() -> (State, Uuid, Uuid, User) { + let state = State::new(); + let connection_id = Uuid::new_v4(); + let file_id = Uuid::new_v4(); + let user = new_user(); + + state.enter_room(file_id, &user, connection_id).await; + + (state, connection_id, file_id, user) + } + + use super::*; + #[tokio::test] + async fn removes_stale_users_in_room() { + let (state, connection_id, file_id, _) = setup().await; + + tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; + + let new_user = new_user(); + state.enter_room(file_id, &new_user, connection_id).await; + state.remove_stale_users_in_room(file_id, 0).await.unwrap(); + assert_eq!(get_room!(state, file_id).unwrap().users.len(), 1); + + tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; + + state.remove_stale_users_in_room(file_id, 0).await.unwrap(); + let expected = format!("Room {file_id} not found"); + assert_anyhow_error(get_room!(state, file_id), &expected); + } + + #[tokio::test] + async fn updates_a_users_heartbeat() { + let (state, _, file_id, user) = setup().await; + + let old_heartbeat = state + ._get_user_in_room(&file_id, &user.session_id) + .await + .unwrap() + .last_heartbeat; + + state + .update_user_heartbeat(file_id, &user.session_id) + .await + .unwrap(); + + let new_heartbeat = state + ._get_user_in_room(&file_id, &user.session_id) + .await + .unwrap() + .last_heartbeat; + + assert!(old_heartbeat < new_heartbeat); + } +} diff --git a/quadratic-multiplayer/src/test_util.rs b/quadratic-multiplayer/src/test_util.rs index 010072c6ea..ed0a6e2818 100644 --- a/quadratic-multiplayer/src/test_util.rs +++ b/quadratic-multiplayer/src/test_util.rs @@ -1,39 +1,90 @@ use fake::faker::filesystem::en::FilePath; +use fake::faker::internet::en::FreeEmail; use fake::faker::name::en::{FirstName, LastName}; use fake::Fake; use futures::stream::StreamExt; use futures_util::SinkExt; +use quadratic_core::controller::operations::operation::Operation; +use quadratic_core::controller::GridController; +use quadratic_core::{Array, CellValue, SheetRect}; use std::sync::Arc; use std::{ + fmt::Debug, future::IntoFuture, net::{Ipv4Addr, SocketAddr}, }; -use tokio_tungstenite::tungstenite; +use tokio::net::TcpStream; +use tokio::sync::Mutex; +use tokio_tungstenite::{tungstenite, MaybeTlsStream, WebSocketStream}; use uuid::Uuid; -use crate::message::MessageRequest; -use crate::state::{State, User}; +use crate::message::request::MessageRequest; +use crate::state::user::{User, UserState}; +use crate::state::State; + +pub(crate) fn assert_anyhow_error(result: anyhow::Result, message: &str) { + let error = result.unwrap_err(); + let root_cause = error.root_cause(); + + assert_eq!(format!("{}", root_cause), message); +} pub(crate) fn new_user() -> User { User { - id: "user".to_string(), + session_id: Uuid::new_v4(), + user_id: Uuid::new_v4().to_string(), first_name: FirstName().fake(), last_name: LastName().fake(), + email: FreeEmail().fake(), + state: UserState { + sheet_id: Uuid::new_v4(), + selection: "".to_string(), + cell_edit: Default::default(), + x: 0.0, + y: 0.0, + visible: false, + viewport: "initial viewport".to_string(), + }, image: FilePath().fake(), socket: None, + last_heartbeat: chrono::Utc::now(), } } -pub(crate) async fn add_user_to_room(file_id: Uuid, user: User, state: Arc) -> User { - state.enter_room(file_id, &user).await; +pub(crate) async fn add_user_to_room( + file_id: Uuid, + user: User, + state: Arc, + connection_id: Uuid, +) -> User { + state.enter_room(file_id, &user, connection_id).await; user } -pub(crate) async fn add_new_user_to_room(file_id: Uuid, state: Arc) -> User { - add_user_to_room(file_id, new_user(), state).await +pub(crate) async fn add_new_user_to_room( + file_id: Uuid, + state: Arc, + connection_id: Uuid, +) -> User { + add_user_to_room(file_id, new_user(), state, connection_id).await +} + +pub(crate) fn grid_setup() -> GridController { + GridController::new() +} + +pub(crate) fn operation(grid: &mut GridController, x: i64, y: i64, value: &str) -> Operation { + let sheet_id = grid.sheet_ids().first().unwrap().to_owned(); + let sheet_rect = SheetRect::single_pos((x, y).into(), sheet_id); + let value = CellValue::Text(value.into()); + let values = Array::from(value); + + Operation::SetCellValues { sheet_rect, values } } -pub(crate) async fn integration_test(state: Arc, request: MessageRequest) -> String { +pub(crate) async fn integration_test_setup( + state: Arc, +) -> WebSocketStream> { let listener = tokio::net::TcpListener::bind(SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0))) .await .unwrap(); @@ -42,20 +93,35 @@ pub(crate) async fn integration_test(state: Arc, request: MessageRequest) // run the server in a separate thread tokio::spawn(axum::serve(listener, crate::server::app(state)).into_future()); - let (mut socket, _response) = tokio_tungstenite::connect_async(format!("ws://{addr}/ws")) + let (socket, _response) = tokio_tungstenite::connect_async(format!("ws://{addr}/ws")) .await .unwrap(); + socket +} + +pub(crate) async fn integration_test_send_and_receive( + socket: Arc>>>, + request: MessageRequest, + expect_response: bool, +) -> Option { // send the message socket + .lock() + .await .send(tungstenite::Message::text( serde_json::to_string(&request).unwrap(), )) .await .unwrap(); + if !expect_response { + return None; + } - match socket.next().await.unwrap().unwrap() { + let response = match socket.lock().await.next().await.unwrap().unwrap() { tungstenite::Message::Text(msg) => msg, other => panic!("expected a text message but got {other:?}"), - } + }; + + Some(response) } diff --git a/quadratic-shared/typesAndSchemas.ts b/quadratic-shared/typesAndSchemas.ts index 94314aa6e8..bd541dda73 100644 --- a/quadratic-shared/typesAndSchemas.ts +++ b/quadratic-shared/typesAndSchemas.ts @@ -1,4 +1,4 @@ -import z from 'zod'; +import * as z from 'zod'; // ============================================================================= // Previously: src/permissions.ts diff --git a/rust-shared/Cargo.toml b/rust-shared/Cargo.toml new file mode 100644 index 0000000000..8f39d4aa2a --- /dev/null +++ b/rust-shared/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rust-shared" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +quadratic-core = { path = "../quadratic-core" } +tabled = { version ="0.14.0", features = ["color"] } + +[dev-dependencies] \ No newline at end of file diff --git a/rust-shared/README.md b/rust-shared/README.md new file mode 100644 index 0000000000..12abf9d838 --- /dev/null +++ b/rust-shared/README.md @@ -0,0 +1,2 @@ +# Shared Rust Utilities + diff --git a/quadratic-core/examples/v1_0.grid b/rust-shared/data/grid/v1_0.grid similarity index 100% rename from quadratic-core/examples/v1_0.grid rename to rust-shared/data/grid/v1_0.grid diff --git a/quadratic-core/examples/v1_1.grid b/rust-shared/data/grid/v1_1.grid similarity index 100% rename from quadratic-core/examples/v1_1.grid rename to rust-shared/data/grid/v1_1.grid diff --git a/quadratic-core/examples/v1_2.grid b/rust-shared/data/grid/v1_2.grid similarity index 100% rename from quadratic-core/examples/v1_2.grid rename to rust-shared/data/grid/v1_2.grid diff --git a/quadratic-core/examples/v1_3.grid b/rust-shared/data/grid/v1_3.grid similarity index 100% rename from quadratic-core/examples/v1_3.grid rename to rust-shared/data/grid/v1_3.grid diff --git a/quadratic-core/examples/v1_3_borders.grid b/rust-shared/data/grid/v1_3_borders.grid similarity index 100% rename from quadratic-core/examples/v1_3_borders.grid rename to rust-shared/data/grid/v1_3_borders.grid diff --git a/quadratic-core/examples/v1_3_fill_color.grid b/rust-shared/data/grid/v1_3_fill_color.grid similarity index 100% rename from quadratic-core/examples/v1_3_fill_color.grid rename to rust-shared/data/grid/v1_3_fill_color.grid diff --git a/quadratic-core/examples/v1_3_multi_column_python.grid b/rust-shared/data/grid/v1_3_multi_column_python.grid similarity index 100% rename from quadratic-core/examples/v1_3_multi_column_python.grid rename to rust-shared/data/grid/v1_3_multi_column_python.grid diff --git a/quadratic-core/examples/v1_3_npm_downloads.grid b/rust-shared/data/grid/v1_3_npm_downloads.grid similarity index 100% rename from quadratic-core/examples/v1_3_npm_downloads.grid rename to rust-shared/data/grid/v1_3_npm_downloads.grid diff --git a/quadratic-core/examples/v1_3_numeric_format.grid b/rust-shared/data/grid/v1_3_numeric_format.grid similarity index 100% rename from quadratic-core/examples/v1_3_numeric_format.grid rename to rust-shared/data/grid/v1_3_numeric_format.grid diff --git a/quadratic-core/examples/v1_3_python.grid b/rust-shared/data/grid/v1_3_python.grid similarity index 100% rename from quadratic-core/examples/v1_3_python.grid rename to rust-shared/data/grid/v1_3_python.grid diff --git a/quadratic-core/examples/c1_3_python_text_only.grid b/rust-shared/data/grid/v1_3_python_text_only.grid similarity index 100% rename from quadratic-core/examples/c1_3_python_text_only.grid rename to rust-shared/data/grid/v1_3_python_text_only.grid diff --git a/quadratic-core/examples/v1_3_single_code_cell.grid b/rust-shared/data/grid/v1_3_single_code_cell.grid similarity index 100% rename from quadratic-core/examples/v1_3_single_code_cell.grid rename to rust-shared/data/grid/v1_3_single_code_cell.grid diff --git a/quadratic-core/examples/v1_3_single_formula.grid b/rust-shared/data/grid/v1_3_single_formula.grid similarity index 100% rename from quadratic-core/examples/v1_3_single_formula.grid rename to rust-shared/data/grid/v1_3_single_formula.grid diff --git a/quadratic-core/examples/v1_4_airports_distance.grid b/rust-shared/data/grid/v1_4_airports_distance.grid similarity index 100% rename from quadratic-core/examples/v1_4_airports_distance.grid rename to rust-shared/data/grid/v1_4_airports_distance.grid diff --git a/quadratic-core/examples/v1_4_full_featured.grid b/rust-shared/data/grid/v1_4_full_featured.grid similarity index 100% rename from quadratic-core/examples/v1_4_full_featured.grid rename to rust-shared/data/grid/v1_4_full_featured.grid diff --git a/quadratic-core/examples/v1_4_simple.grid b/rust-shared/data/grid/v1_4_simple.grid similarity index 100% rename from quadratic-core/examples/v1_4_simple.grid rename to rust-shared/data/grid/v1_4_simple.grid diff --git a/rust-shared/data/grid/v1_5_simple.grid b/rust-shared/data/grid/v1_5_simple.grid new file mode 100644 index 0000000000..ccadf987de --- /dev/null +++ b/rust-shared/data/grid/v1_5_simple.grid @@ -0,0 +1,275 @@ +{ + "sheets": [ + { + "id": { + "id": "753b4e8a-d875-431f-8085-cf0867014bd1" + }, + "name": "Sheet 1", + "color": null, + "order": "a0", + "offsets": [ + [], + [] + ], + "columns": [ + [ + 0, + { + "x": 0, + "values": { + "0": { + "y": 0, + "content": { + "Values": [ + { + "type": "text", + "value": "abc" + } + ] + } + } + }, + "spills": {}, + "align": {}, + "wrap": {}, + "numeric_format": {}, + "numeric_decimals": {}, + "numeric_commas": {}, + "bold": {}, + "italic": {}, + "text_color": {}, + "fill_color": {},"render_size": {} + } + ], + [ + 1, + { + "x": 1, + "values": {}, + "spills": {}, + "align": {}, + "wrap": {}, + "numeric_format": {}, + "numeric_decimals": {}, + "numeric_commas": {}, + "bold": {}, + "italic": {}, + "text_color": {}, + "fill_color": {},"render_size": {} + } + ], + [ + 4, + { + "x": 4, + "values": {}, + "spills": { + "7": { + "y": 7, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + }, + "4": { + "y": 4, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + }, + "10": { + "y": 10, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + }, + "5": { + "y": 5, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + }, + "3": { + "y": 3, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + }, + "11": { + "y": 11, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + }, + "2": { + "y": 2, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + }, + "8": { + "y": 8, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + }, + "9": { + "y": 9, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + }, + "6": { + "y": 6, + "content": { + "value": "{\"sheet\":{\"id\":\"753b4e8a-d875-431f-8085-cf0867014bd1\"},\"column\":0,\"row\":0}", + "len": 1 + } + } + }, + "align": {}, + "wrap": {}, + "numeric_format": {}, + "numeric_decimals": {}, + "numeric_commas": {}, + "bold": {}, + "italic": {}, + "text_color": {}, + "fill_color": {}, + "render_size": {} + } + ], + [ + 5, + { + "x": 5, + "values": {}, + "spills": {}, + "align": {}, + "wrap": {}, + "numeric_format": {}, + "numeric_decimals": {}, + "numeric_commas": {}, + "bold": {}, + "italic": {}, + "text_color": {}, + "fill_color": {}, + "render_size": {} + } + ], + [ + 6, + { + "x": 6, + "values": { + "4": { + "y": 4, + "content": { + "Values": [ + { + "type": "number", + "value": "1" + } + ] + } + } + }, + "spills": {}, + "align": {}, + "wrap": {}, + "numeric_format": {}, + "numeric_decimals": {}, + "numeric_commas": {}, + "bold": {}, + "italic": {}, + "text_color": {}, + "fill_color": {}, + "render_size": {} + } + ] + ], + "borders": {}, + "code_cells": [ + [ + { + "sheet": { + "id": "753b4e8a-d875-431f-8085-cf0867014bd1" + }, + "x": 0, + "y": 0 + }, + { + "language": "Python", + "code_string": "out = []\\nfor x in range(10):\\n out.append(x)\\n\\n# Last line returns to the sheet\\nout\\n# [out] # Wrap in array to expand horizontally", + "formatted_code_string": "out = []\\nfor x in range(10):\\n out.append(x)\\n\\n# Last line returns to the sheet\\nout\\n# [out] # Wrap in array to expand horizontally\\n", + "last_modified": "", + "output": { + "stdOut": "", + "result": { + "output_value": { + "size": { + "w": 1, + "h": 10 + }, + "values": [ + { + "type": "text", + "value": "0" + }, + { + "type": "text", + "value": "1" + }, + { + "type": "text", + "value": "2" + }, + { + "type": "text", + "value": "3" + }, + { + "type": "text", + "value": "4" + }, + { + "type": "text", + "value": "5" + }, + { + "type": "text", + "value": "6" + }, + { + "type": "text", + "value": "7" + }, + { + "type": "text", + "value": "8" + }, + { + "type": "text", + "value": "9" + } + ] + }, + "cells_accessed": [] + }, + "spill": false + } + } + ] + ] + } + ], + "version": "1.5" +} \ No newline at end of file diff --git a/rust-shared/src/lib.rs b/rust-shared/src/lib.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/rust-shared/src/lib.rs @@ -0,0 +1 @@ + diff --git a/vercel.json b/vercel.json index d63568a6fc..2bae050866 100644 --- a/vercel.json +++ b/vercel.json @@ -1,4 +1,5 @@ { - "buildCommand": "./scripts/run-ci-build.sh", - "installCommand": "npm install" + "buildCommand": "./infra/client/build-client-ci.sh", + "installCommand": "npm install", + "outputDirectory": "build" }